Skip to content

Commit

Permalink
Init command
Browse files Browse the repository at this point in the history
  • Loading branch information
viaszkadi committed Oct 19, 2024
1 parent fcfc238 commit 28a5719
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 1 deletion.
11 changes: 10 additions & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "979e58bf8de276e032be54bbee652a49a1e83b7f0df0fd166dcf73870bb4c0bc",
"originHash" : "d101b76e76d5b8396c0ead4a02b4bf6d6fcfc434915b3b10b0208df2f4f05e7c",
"pins" : [
{
"identity" : "async-http-client",
Expand Down Expand Up @@ -252,6 +252,15 @@
"revision" : "3036ba9d69cf1fd04d433527bc339dc0dc75433d",
"version" : "5.1.3"
}
},
{
"identity" : "zipfoundation",
"kind" : "remoteSourceControl",
"location" : "https://github.com/weichsel/ZIPFoundation.git",
"state" : {
"revision" : "02b6abe5f6eef7e3cbd5f247c5cc24e246efcfe0",
"version" : "0.9.19"
}
}
],
"version" : 3
Expand Down
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ let package = Package(
.package(url: "https://github.com/hummingbird-project/swift-mustache", from: "2.0.0"),
.package(url: "https://github.com/jpsim/Yams", from: "5.1.0"),
.package(url: "https://github.com/scinfu/SwiftSoup", from: "2.7.0"),
.package(url: "https://github.com/weichsel/ZIPFoundation.git", from: "0.9.0"),
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.23.1"),
] + deps,
targets: [
.executableTarget(
Expand All @@ -45,6 +47,8 @@ let package = Package(
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "Hummingbird", package: "hummingbird"),
.product(name: "ZIPFoundation", package: "ZIPFoundation"),
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.target(name: "ToucanSDK"),
] + tdeps
),
Expand Down
144 changes: 144 additions & 0 deletions Sources/toucan-cli/Commands/Init.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import Foundation
import ArgumentParser
import ToucanSDK
import Logging
import FileManagerKit
import ZIPFoundation
import AsyncHTTPClient
import NIOFoundationCompat

extension Entrypoint {

struct Init: AsyncParsableCommand {

@Argument(help: "The name of the site directory (default: site).")
var siteDirectory: String = "site"

@Option(name: .shortAndLong, help: "The log level to use.")
var logLevel: Logger.Level = .info

func run() async throws {
var logger = Logger(label: "toucan")
logger.logLevel = logLevel

let siteExists = fileManager.directoryExists(at: siteDirUrl)

guard !siteExists else {
logger.error("Folder already exists: \(siteDirUrl)")
return
}

do {
let source = Download(
sourceUrl: exampleSourceUrl,
targetDirUrl: siteDirUrl,
fileManager: fileManager
)
let theme = Download(
sourceUrl: exampleThemeUrl,
targetDirUrl: themesDefaultDirUrl,
fileManager: fileManager
)

try await source.resolve()
try await theme.resolve()

logger.info("'\(siteDirectory)' was created successfully.")
}
catch {
logger.error("\(String(describing: error))")
}
}
}
}

extension Entrypoint.Init {

var fileManager: FileManager { .default }

var currentDirUrl: URL {
URL(fileURLWithPath: fileManager.currentDirectoryPath)
}

var siteDirUrl: URL {
currentDirUrl.appending(path: siteDirectory)
}

var exampleSourceUrl: URL {
.init(
string:
"https://github.com/toucansites/minimal-example/archive/refs/heads/main.zip"
)!
}

var exampleThemeUrl: URL {
.init(
string:
"https://github.com/toucansites/minimal-theme/archive/refs/heads/main.zip"
)!
}

var themesDefaultDirUrl: URL {
siteDirUrl.appending(path: "src/themes/default")
}
}

extension Entrypoint.Init {

struct Download {

let id = UUID().uuidString
let sourceUrl: URL
let targetDirUrl: URL
let fileManager: FileManager

private var url: URL {
fileManager.temporaryDirectory.appending(path: id)
}

private var zipUrl: URL {
url.appendingPathExtension("zip")
}

func resolve() async throws {
/// Downloading the ZIP file into a temporary directory.
let client = HTTPClient(eventLoopGroupProvider: .singleton)
defer { _ = client.shutdown() }

let request = try HTTPClient.Request(
url: sourceUrl.absoluteString,
method: .GET
)
let response = try await client.execute(request: request).get()

guard
var body = response.body,
let data = body.readData(length: body.readableBytes)
else {
throw URLError(.badServerResponse)
}

try data.write(to: zipUrl)

/// Unzipping the file to a temporary directory.
try fileManager.unzipItem(at: zipUrl, to: url)

/// Emptying the target directory. Git submodules can cause issues.
try? fileManager.removeItem(at: targetDirUrl)

/// Finding the root directory URL.
let items = fileManager.listDirectory(at: url)
guard let rootDirName = items.first else {
throw URLError(.cannotParseResponse)
}
let rootDirUrl = url.appending(path: rootDirName)

/// Moving files to the target directory.
try fileManager.moveItem(at: rootDirUrl, to: targetDirUrl)

/// Cleaning up unnecessary files.
try? fileManager.delete(at: zipUrl)
try? fileManager.delete(at: url)
}
}
}
1 change: 1 addition & 0 deletions Sources/toucan-cli/Entrypoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct Entrypoint: AsyncParsableCommand {
Generate.self,
Serve.self,
Watch.self,
Init.self,
]
)
}

0 comments on commit 28a5719

Please sign in to comment.