aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRuben Beltran del Rio <ruben@unlimited.pizza>2022-12-09 14:43:41 +0100
committerRuben Beltran del Rio <ruben@unlimited.pizza>2022-12-09 14:43:41 +0100
commitc5cbbd3835ccd509179504cdf7d5e74356d7dca5 (patch)
treef5588fce8924772a54f599c5636640731bab640d /lib
parent24de2f063e5dfcad0086d1dc81de3cf012a00e4c (diff)
Add rudimentary sync support
Diffstat (limited to 'lib')
-rw-r--r--lib/blog.js102
-rw-r--r--lib/remote.js48
-rw-r--r--lib/remotes/git.js30
3 files changed, 157 insertions, 23 deletions
diff --git a/lib/blog.js b/lib/blog.js
index 6b831f7..ba9ae53 100644
--- a/lib/blog.js
+++ b/lib/blog.js
@@ -1,8 +1,7 @@
'use strict';
-const { access, mkdir, readdir, readFile, rm, writeFile } = require('fs/promises');
+const { access, cp, mkdir, readdir, readFile, rm, writeFile } = require('fs/promises');
const { exec } = require('child_process');
-const { ncp } = require('ncp');
const { basename, resolve, join } = require('path');
const ParseGemini = require('gemini-to-html/parse');
const RenderGemini = require('gemini-to-html/render');
@@ -19,11 +18,14 @@ const TXTGenerator = require('./generators/txt');
const GemlogArchiver = require('./archivers/gemlog');
+// Remote Handler
+
+const Remote = require('./remote');
+
const internals = {
// Promisified functions
exec: promisify(exec),
- ncp: promisify(ncp),
debuglog: debuglog('blog'),
@@ -69,6 +71,10 @@ module.exports = class Blog {
async add(postLocation) {
await this._ensurePostsDirectoryExists();
+ try {
+ await this.syncDown();
+ }
+ catch {};
await this._shift();
await this._ensurePostsDirectoryExists(join(this.postsDirectory, '0'));
await this.update(postLocation);
@@ -86,6 +92,10 @@ module.exports = class Blog {
*/
async update(postLocation) {
+ try {
+ await this.syncDown();
+ }
+ catch {};
const metadata = await this._getMetadata();
await this._ensurePostsDirectoryExists();
await this._copyPost(postLocation);
@@ -94,6 +104,10 @@ module.exports = class Blog {
await this._archive(postLocation);
await this.generate();
+ try {
+ await this.syncUp();
+ }
+ catch {};
}
/**
@@ -158,6 +172,55 @@ module.exports = class Blog {
internals.debuglog('Finished publishing');
}
+ /**
+ * Adds a remote
+ *
+ * @function addRemote
+ * @memberof Blog
+ * @return {Promise<undefined>} empty promise, returns no value
+ * @instance
+ */
+ async addRemote(remote) {
+ await Remote.add(this.remoteConfig, remote)
+ }
+
+ /**
+ * Removes a remote
+ *
+ * @function removeRemote
+ * @memberof Blog
+ * @return {Promise<undefined>} empty promise, returns no value
+ * @instance
+ */
+ async removeRemote() {
+ await Remote.remove(this.remoteConfig)
+ }
+
+
+ /**
+ * Pulls the posts and archive from the remote
+ *
+ * @function syncDown
+ * @memberof Blog
+ * @return {Promise<undefined>} empty promise, returns no value
+ * @instance
+ */
+ async syncDown() {
+ await Remote.syncDown(this.remoteConfig, this.blogDirectory)
+ }
+
+ /**
+ * Pushes the posts and archive to the remote
+ *
+ * @function syncUp
+ * @memberof Blog
+ * @return {Promise<undefined>} empty promise, returns no value
+ * @instance
+ */
+ async syncUp() {
+ await Remote.syncUp(this.remoteConfig, this.blogDirectory)
+ }
+
// Parses Gemini for each page, copies assets and generates index.
async generate() {
@@ -238,7 +301,7 @@ module.exports = class Blog {
await access(sourcePath); // check the source path
internals.debuglog(`Shifting blog post ${sourcePath} to ${targetPath}`);
- await internals.ncp(sourcePath, targetPath);
+ await cp(sourcePath, targetPath, { recursive: true });
}
catch (error) {
if (error.code === internals.kFileNotFoundError) {
@@ -260,16 +323,12 @@ module.exports = class Blog {
const targetPath = join(this.archiveDirectory, post.id);
- try {
- internals.debuglog(`Removing ${targetPath}`);
- await rm(targetPath, { recursive: true });
- }
- finally {
- internals.debuglog(`Adding ${post.location} to ${targetPath}`);
- await this._ensureDirectoryExists(targetPath);
- await internals.ncp(post.location, targetPath);
- internals.debuglog(`Added ${post.location} to ${targetPath}`);
- }
+ internals.debuglog(`Removing ${targetPath}`);
+ await rm(targetPath, { recursive: true, force: true });
+ internals.debuglog(`Adding ${post.location} to ${targetPath}`);
+ await this._ensureDirectoryExists(targetPath);
+ await cp(post.location, targetPath, { recursive: true });
+ internals.debuglog(`Added ${post.location} to ${targetPath}`);
}
// Attempts to read existing metadata. Otherwise generates new set.
@@ -313,14 +372,11 @@ module.exports = class Blog {
const targetPost = join(targetPath, postName);
internals.debuglog(`Removing ${targetPath}`);
- try {
- await rm(targetPath, { recursive: true });
- }
- finally {
- await this._ensureDirectoryExists(targetPath);
- internals.debuglog(`Adding ${postLocation} to ${targetPost}`);
- await internals.ncp(postLocation, targetPost);
- }
+ await rm(targetPath, { recursive: true, force: true });
+ await this._ensureDirectoryExists(targetPath);
+ internals.debuglog(`Adding ${postLocation} to ${targetPost}`);
+ await cp(postLocation, targetPost, { recursive: true });
+ internals.debuglog(`Added ${postLocation} to ${targetPath}`);
}
// Ensures a directory exists.
@@ -334,7 +390,7 @@ module.exports = class Blog {
catch (error) {
if (error.code === internals.kFileNotFoundError) {
internals.debuglog(`Creating ${directory}`);
- await mkdir(directory);
+ await mkdir(directory, { recursive: true });
return;
}
diff --git a/lib/remote.js b/lib/remote.js
new file mode 100644
index 0000000..d8f73f9
--- /dev/null
+++ b/lib/remote.js
@@ -0,0 +1,48 @@
+const { readFile, rm, writeFile } = require('fs/promises');
+
+const internals = {
+ strings: {
+ configurationNotFound: 'Remote configuration not set, consult help for more info.'
+ },
+ strategies: [
+ require('./remotes/git')
+ ]
+};
+
+module.exports = {
+ async add(remoteConfig, remote) {
+ await writeFile(remoteConfig, remote);
+ },
+
+ async remove(remoteConfig) {
+ await rm(remoteConfig, { force: true })
+ },
+
+ async syncUp(remoteConfig, blogDirectory) {
+ this._executeMethodOnStrategy(remoteConfig, 'syncUp', blogDirectory);
+ },
+
+ async syncDown(remoteConfig, blogDirectory) {
+ this._executeMethodOnStrategy(remoteConfig, 'syncDown', blogDirectory);
+ },
+
+ async _executeMethodOnStrategy(remoteConfig, method, blogDirectory) {
+ const remote = await this._ensureConfiguration(remoteConfig);
+
+ for (const strategy of internals.strategies) {
+ if (strategy.canHandle(remote)) {
+ await strategy[method](remote, blogDirectory);
+ }
+ }
+ },
+
+ async _ensureConfiguration(remoteConfig) {
+ try {
+ const configuration = await readFile(remoteConfig, { encoding: 'utf8' });
+ return configuration;
+ }
+ catch {
+ throw new Error(internals.strings.configurationNotFound);
+ }
+ }
+}
diff --git a/lib/remotes/git.js b/lib/remotes/git.js
new file mode 100644
index 0000000..d8e0cfd
--- /dev/null
+++ b/lib/remotes/git.js
@@ -0,0 +1,30 @@
+const { exec } = require('child_process');
+const { debuglog, promisify } = require('util');
+
+const internals = {
+ // Promisified functions
+ exec: promisify(exec),
+
+ debuglog: debuglog('blog'),
+};
+
+module.exports = {
+ canHandle() {
+ // For the future: actually check if it's a valid git url
+ return true;
+ },
+
+ async syncUp(remote, blogDirectory) {
+ await internals.exec(`cd ${blogDirectory} && git init`);
+ await internals.exec(`cd ${blogDirectory} && git add .`);
+ await internals.exec(`cd ${blogDirectory} && git commit --allow-empty -m blog-sync-up-${Date.now()}`);
+ await internals.exec(`cd ${blogDirectory} && git push ${remote} main --force`);
+ },
+
+ async syncDown(remote, blogDirectory) {
+ await internals.exec(`cd ${blogDirectory} && git init`);
+ await internals.exec(`cd ${blogDirectory} && git checkout .`);
+ await internals.exec(`cd ${blogDirectory} && git clean . -f`);
+ await internals.exec(`cd ${blogDirectory} && git pull ${remote} main`);
+ }
+}