diff --git a/package.json b/package.json index 24108a9..3b29e49 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "scripts": { "make-link": "node --no-warnings ./scripts/make_dev_link.js", "dev": "vite build --watch", - "build": "vite build" + "build": "vite build", + "install": "vite build && node --no-warnings ./scripts/make_install.js" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^2.4.1", diff --git a/scripts/make_install.js b/scripts/make_install.js new file mode 100644 index 0000000..9c2cd9b --- /dev/null +++ b/scripts/make_install.js @@ -0,0 +1,191 @@ +import fs from 'fs'; +import path from 'path'; +import http from 'node:http'; +import readline from 'node:readline'; + + +//************************************ Write you dir here ************************************ + +let targetDir = ''; // the target directory of the plugin, '*/data/plugin' +//******************************************************************************************** + +const log = (info) => console.log(`\x1B[36m%s\x1B[0m`, info); +const error = (info) => console.log(`\x1B[31m%s\x1B[0m`, info); + +let POST_HEADER = { + // "Authorization": `Token ${token}`, + "Content-Type": "application/json", +} + +async function myfetch(url, options) { + //使用 http 模块,从而兼容那些不支持 fetch 的 nodejs 版本 + return new Promise((resolve, reject) => { + let req = http.request(url, options, (res) => { + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + res.on('end', () => { + resolve({ + ok: true, + status: res.statusCode, + json: () => JSON.parse(data) + }); + }); + }); + req.on('error', (e) => { + reject(e); + }); + req.end(); + }); +} + +async function getSiYuanDir() { + let url = 'http://127.0.0.1:6806/api/system/getWorkspaces'; + let conf = {}; + try { + let response = await myfetch(url, { + method: 'POST', + headers: POST_HEADER + }); + if (response.ok) { + conf = await response.json(); + } else { + error(`\tHTTP-Error: ${response.status}`); + return null; + } + } catch (e) { + error(`\tError: ${e}`); + error("\tPlease make sure SiYuan is running!!!"); + return null; + } + return conf.data; +} + +async function chooseTarget(workspaces) { + let count = workspaces.length; + log(`>>> Got ${count} SiYuan ${count > 1 ? 'workspaces' : 'workspace'}`) + for (let i = 0; i < workspaces.length; i++) { + log(`\t[${i}] ${workspaces[i].path}`); + } + + if (count == 1) { + return `${workspaces[0].path}/data/plugins`; + } else { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + let index = await new Promise((resolve, reject) => { + rl.question(`\tPlease select a workspace[0-${count-1}]: `, (answer) => { + resolve(answer); + }); + }); + rl.close(); + return `${workspaces[index].path}/data/plugins`; + } +} + +log('>>> Try to visit constant "targetDir" in make_install.js...') + +if (targetDir === '') { + log('>>> Constant "targetDir" is empty, try to get SiYuan directory automatically....') + let res = await getSiYuanDir(); + + if (res === null || res === undefined || res.length === 0) { + error('>>> Can not get SiYuan directory automatically'); + + process.exit(1); + } else { + targetDir = await chooseTarget(res); + } + + log(`>>> Successfully got target directory: ${targetDir}`); +} + +//Check +if (!fs.existsSync(targetDir)) { + error(`Failed! plugin directory not exists: "${targetDir}"`); + error(`Please set the plugin directory in scripts/make_install.js`); + process.exit(1); +} + + +//check if plugin.json exists +if (!fs.existsSync('./plugin.json')) { + //change dir to parent + process.chdir('../'); + if (!fs.existsSync('./plugin.json')) { + error('Failed! plugin.json not found'); + process.exit(1); + } +} + +//load plugin.json +const plugin = JSON.parse(fs.readFileSync('./plugin.json', 'utf8')); +const name = plugin?.name; +if (!name || name === '') { + error('Failed! Please set plugin name in plugin.json'); + process.exit(1); +} + +const distDir = `${process.cwd()}/dist`; +//mkdir if not exists +if (!fs.existsSync(distDir)) { + fs.mkdirSync(distDir); +} + +function cmpPath(path1, path2) { + path1 = path1.replace(/\\/g, '/'); + path2 = path2.replace(/\\/g, '/'); + // sepertor at tail + if (path1[path1.length - 1] !== '/') { + path1 += '/'; + } + if (path2[path2.length - 1] !== '/') { + path2 += '/'; + } + return path1 === path2; +} + +const targetPath = `${targetDir}/${name}`; + + +function copyDirectory(srcDir, dstDir) { + if (!fs.existsSync(dstDir)) { + fs.mkdirSync(dstDir); + log(`Created directory ${dstDir}`); + } + //将 distDir 下的所有文件复制到 targetPath + fs.readdir(srcDir, { withFileTypes: true }, (err, files) => { + if (err) { + error('Error reading source directory:', err); + return; + } + + // 遍历源目录中的所有文件和子目录 + files.forEach((file) => { + const src = path.join(srcDir, file.name); + const dst = path.join(dstDir, file.name); + + // 判断当前项是文件还是目录 + if (file.isDirectory()) { + // 如果是目录,则递归调用复制函数复制子目录 + copyDirectory(src, dst); + } else { + // 如果是文件,则复制文件到目标目录 + fs.copyFile(src, dst, (err) => { + if (err) { + error('Error copying file:' + err); + } else { + log(`Copied file: ${src} --> ${dst}`); + } + }); + } + }); + log(`Copied ${distDir} to ${targetPath}`); + }); +} +copyDirectory(distDir, targetPath); + +