+ internals.debuglog('Generating output');
+
+ const posts = await this._readPosts();
+
+ // Start from a clean slate.
+ await rmIfExists(this.blogOutputDirectory);
+ await ensureDirectoryExists(this.blogOutputDirectory);
+
+ // Run each generator
+ await StaticGenerator(this.staticDirectory, this.blogOutputDirectory, posts);
+ await HTMLGenerator(await this._templateDirectoryFor('index.html'), this.blogOutputDirectory, posts);
+ await RSSGenerator(await this._templateDirectoryFor('feed.xml'), this.blogOutputDirectory, posts);
+ await TXTGenerator(await this._templateDirectoryFor('index.txt'), this.blogOutputDirectory, posts);
+
+ // Start from a clean slate.
+ await rmIfExists(this.archiveOutputDirectory);
+ await ensureDirectoryExists(this.archiveOutputDirectory);
+ await ensureDirectoryExists(this.archiveDirectory);
+
+ // Run each archiver
+ await GemlogArchiver(await this._templateDirectoryFor('index.gmi'), this.archiveDirectory, this.archiveOutputDirectory);
+ // TODO: GopherArchiver
+ }
+
+ // Reads the posts into an array
+
+ async _readPosts() {
+
+ internals.debuglog('Reading posts');
+ const posts = [];
+
+ for (let i = 0; i < this.maxPosts; ++i) {
+ try {
+ posts.push(await this._readPost(i));
+ }
+ catch (error) {
+ if (error.code === kFileNotFoundError) {
+ internals.debuglog(`Skipping ${i}`);
+ continue;
+ }
+
+ throw error;
+ }
+ }
+
+ return posts;
+ }
+
+ // Reads an individual post
+
+ async _readPost(index = 0) {
+
+ const postSourcePath = join(this.postsDirectory, `${index}`);
+
+ internals.debuglog(`Reading ${postSourcePath}`);
+
+ await access(postSourcePath);
+
+ const metadata = await this._getMetadata(index);
+
+ const postContentPath = await this._findBlogContent(postSourcePath);
+ internals.debuglog(`Reading ${postContentPath}`);
+ const postContent = await readFile(postContentPath, { encoding: 'utf8' });
+
+ internals.debuglog('Parsing Gemini');
+ return {
+ ...metadata,
+ location: postSourcePath,
+ index,
+ html: RenderGemini(ParseGemini(postContent)),
+ raw: postContent
+ };