UNPKG

@mieweb/wikigdrive

Version:

Google Drive to MarkDown synchronization

148 lines (130 loc) 4.73 kB
import path from 'node:path'; import fs from 'node:fs'; import {exec} from 'node:child_process'; import yaml from 'js-yaml'; import {FileContentService} from '../../utils/FileContentService.ts'; import {HugoTheme} from '../server/routes/ConfigController.ts'; import {FRONTMATTER_DUMP_OPTS} from '../transform/frontmatters/frontmatter.ts'; import {convertActionYaml} from '../action/ActionRunnerContainer.ts'; import {RewriteRule} from '../../odt/applyRewriteRule.ts'; async function execAsync(command: string) { const err = new Error(); const stackList = err.stack.split('\n'); await new Promise<{ stdout: string, stderr: string }>((resolve, reject) => { exec(command, (error, stdout, stderr) => { if (stdout) { console.log(stdout); } if (stderr) { console.error(stderr); } if (error) { const err = new Error(error.message); err.stack = stackList.slice(0, 1).concat(stackList.slice(2)).join('\n'); return reject(err); } resolve({ stdout, stderr }); }); }); } export class UserConfig { remote_branch: string; hugo_theme?: HugoTheme; config_toml?: string; transform_subdir?: string; use_google_markdowns?: boolean; auto_sync?: boolean; fm_without_version?: boolean; actions_yaml?: string; rewrite_rules?: RewriteRule[]; preview_rewrite_rule?: string; companion_files_rule?: string; } const DEFAULT_CONFIG: UserConfig = { remote_branch: 'main', hugo_theme: { id: 'ananke', name: 'Anake', url: 'https://github.com/budparr/gohugo-theme-ananke.git', preview_img: 'https://raw.githubusercontent.com/budparr/gohugo-theme-ananke/master/images/screenshot.png' } }; const DEFAULT_REWRITE_RULES = [ { mode: 'MD', tag: 'A', match: '$alt', template: '$href', }, { mode: 'MD', match: '(?:https?:\\/\\/)?(?:www\\.)?(?:youtube\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?)\\/|\\S*?[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})', replace: '(?:https?:\\/\\/)?(?:www\\.)?(?:youtube\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?)\\/|\\S*?[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})', template: '[$label](https://youtube.be/$value)' } ]; export class UserConfigService { public config: UserConfig; constructor(private fileService: FileContentService, private driveId?: string) {} async load(): Promise<UserConfig> { if (await this.fileService.exists('.user_config.json')) { const json = await this.fileService.readJson('.user_config.json'); this.config = json || {}; } else { this.config = structuredClone(DEFAULT_CONFIG); await this.save(); } const workflow = await convertActionYaml(this.config.actions_yaml); this.config.actions_yaml = yaml.dump(workflow, FRONTMATTER_DUMP_OPTS); if (!this.config.rewrite_rules || this.config.rewrite_rules.length === 0) { this.config.rewrite_rules = DEFAULT_REWRITE_RULES; } if (!this.config.companion_files_rule) { this.config.companion_files_rule = '(file.path == "content/navigation.md") || (file.path == "content/toc.md") || (commit.id && file.redirectTo == commit.id) || (commit.redirectTo == file.id && file.id)'; } if (!this.config.preview_rewrite_rule) { const driveId = this.driveId || this.fileService.getRealPath().split('/').pop(); const match = '^(.*)(\\.md|\\/_index\\.md)$'; const replace = process.env.DOMAIN + '/preview/' + driveId + '$1'; this.config.preview_rewrite_rule = `!${match}!${replace}!`; } return this.config; } async save(): Promise<void> { await this.fileService.writeJson('.user_config.json', this.config); await this.genKeys(); } async getDeployPrivateKeyPath() { if (await this.fileService.exists('.private/id_rsa')) { const fullPath = path.join(this.fileService.getRealPath(), '.private', 'id_rsa'); fs.chmodSync(fullPath, '0600'); return fullPath; } return null; } async getDeployKey() { if (await this.fileService.exists('.private/id_rsa.pub')) { return await this.fileService.readFile('.private/id_rsa.pub'); } return null; } async genKeys(force = false) { const privatePath = path.join(this.fileService.getRealPath(), '.private'); if (!fs.existsSync(privatePath)) { fs.mkdirSync(privatePath); } else { if (!force) { return; } } if (fs.existsSync(`${privatePath}/id_rsa`)) { fs.unlinkSync(`${privatePath}/id_rsa`); } if (fs.existsSync(`${privatePath}/id_rsa.pub`)) { fs.unlinkSync(`${privatePath}/id_rsa.pub`); } await execAsync(`ssh-keygen -t ecdsa -b 521 -f ${privatePath}/id_rsa -q -N ""`); } }