You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-09-16 08:56:40 +02:00
2
packages/default-plugins/.eslintignore
Normal file
2
packages/default-plugins/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
plugin-base-repo/
|
||||
plugin-sources/*
|
2
packages/default-plugins/.gitignore
vendored
Normal file
2
packages/default-plugins/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
built-plugins/
|
||||
plugin-sources/*
|
31
packages/default-plugins/build.ts
Normal file
31
packages/default-plugins/build.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import buildAll from './commands/buildAll';
|
||||
import editPatch from './commands/editPatch';
|
||||
const yargs = require('yargs');
|
||||
|
||||
|
||||
const build = () => {
|
||||
yargs
|
||||
.usage('$0 <cmd> [args]')
|
||||
.command('build <outputDir>', 'build all', (yargs: any) => {
|
||||
yargs.positional('outputDir', {
|
||||
type: 'string',
|
||||
describe: 'Path to the parent directory for built output',
|
||||
});
|
||||
}, async (args: any) => {
|
||||
await buildAll(args.outputDir);
|
||||
process.exit(0);
|
||||
})
|
||||
.command('patch <plugin>', 'Edit the patch file for the given plugin ID', (yargs: any) => {
|
||||
yargs.positional('plugin', {
|
||||
type: 'string',
|
||||
describe: 'ID of the plugin to patch',
|
||||
});
|
||||
}, async (args: any) => {
|
||||
await editPatch(args.plugin, null);
|
||||
process.exit(0);
|
||||
})
|
||||
.help()
|
||||
.argv;
|
||||
};
|
||||
|
||||
build();
|
124
packages/default-plugins/buildDefaultPlugins.ts
Normal file
124
packages/default-plugins/buildDefaultPlugins.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { copy, exists, remove, mkdirp, readdir, mkdtemp, readFile, writeFile } from 'fs-extra';
|
||||
import { join, resolve, basename } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { chdir, cwd } from 'process';
|
||||
import { execCommand } from '@joplin/utils';
|
||||
import { glob } from 'glob';
|
||||
import readRepositoryJson from './utils/readRepositoryJson';
|
||||
import waitForCliInput from './utils/waitForCliInput';
|
||||
import getPathToPatchFileFor from './utils/getPathToPatchFileFor';
|
||||
|
||||
type BeforeEachInstallCallback = (buildDir: string, pluginName: string)=> Promise<void>;
|
||||
|
||||
const buildDefaultPlugins = async (outputParentDir: string|null, beforeInstall: BeforeEachInstallCallback) => {
|
||||
const pluginSourcesDir = resolve(join(__dirname, 'plugin-sources'));
|
||||
const pluginRepositoryData = await readRepositoryJson(join(__dirname, 'pluginRepositories.json'));
|
||||
|
||||
const originalDirectory = cwd();
|
||||
|
||||
const logStatus = (...message: string[]) => {
|
||||
const blue = '\x1b[96m';
|
||||
const reset = '\x1b[0m';
|
||||
console.log(blue, ...message, reset);
|
||||
};
|
||||
|
||||
for (const pluginId in pluginRepositoryData) {
|
||||
const repositoryData = pluginRepositoryData[pluginId];
|
||||
|
||||
const buildDir = await mkdtemp(join(tmpdir(), 'default-plugin-build'));
|
||||
try {
|
||||
logStatus('Building plugin', pluginId, 'at', buildDir);
|
||||
const pluginDir = resolve(join(pluginSourcesDir, pluginId));
|
||||
|
||||
// Clone the repository if not done yet
|
||||
if (!(await exists(pluginDir)) || (await readdir(pluginDir)).length === 0) {
|
||||
logStatus(`Cloning from repository ${repositoryData.cloneUrl}`);
|
||||
await execCommand(['git', 'clone', '--', repositoryData.cloneUrl, pluginDir]);
|
||||
chdir(pluginDir);
|
||||
}
|
||||
|
||||
chdir(pluginDir);
|
||||
const currentCommitHash = (await execCommand(['git', 'rev-parse', 'HEAD~'])).trim();
|
||||
const expectedCommitHash = repositoryData.commit;
|
||||
|
||||
if (currentCommitHash !== expectedCommitHash) {
|
||||
logStatus(`Switching to commit ${expectedCommitHash}`);
|
||||
await execCommand(['git', 'switch', repositoryData.branch]);
|
||||
await execCommand(['git', 'checkout', expectedCommitHash]);
|
||||
}
|
||||
|
||||
logStatus('Copying repository files...');
|
||||
await copy(pluginDir, buildDir, {
|
||||
filter: fileName => {
|
||||
return basename(fileName) !== '.git';
|
||||
},
|
||||
});
|
||||
|
||||
chdir(buildDir);
|
||||
|
||||
logStatus('Initializing repository.');
|
||||
await execCommand('git init . -b main');
|
||||
|
||||
logStatus('Marking manifest as built-in');
|
||||
const manifestFile = './src/manifest.json';
|
||||
const manifest = JSON.parse(await readFile(manifestFile, 'utf8'));
|
||||
manifest._built_in = true;
|
||||
await writeFile(manifestFile, JSON.stringify(manifest, undefined, '\t'));
|
||||
|
||||
logStatus('Creating initial commit.');
|
||||
await execCommand('git add .');
|
||||
await execCommand(['git', 'config', 'user.name', 'Build script']);
|
||||
await execCommand(['git', 'config', 'user.email', '']);
|
||||
await execCommand(['git', 'commit', '-m', 'Initial commit']);
|
||||
|
||||
const patchFile = getPathToPatchFileFor(pluginId);
|
||||
if (await exists(patchFile)) {
|
||||
logStatus('Applying patch.');
|
||||
await execCommand(['git', 'apply', patchFile]);
|
||||
}
|
||||
|
||||
await beforeInstall(buildDir, pluginId);
|
||||
|
||||
logStatus('Installing dependencies.');
|
||||
await execCommand('npm install');
|
||||
|
||||
const jplFiles = await glob('publish/*.jpl');
|
||||
logStatus(`Found built .jpl files: ${JSON.stringify(jplFiles)}`);
|
||||
|
||||
if (jplFiles.length === 0) {
|
||||
throw new Error(`No published files found in ${buildDir}/publish`);
|
||||
}
|
||||
|
||||
if (outputParentDir !== null) {
|
||||
logStatus(`Checking output directory in ${outputParentDir}`);
|
||||
const outputDirectory = join(outputParentDir, pluginId);
|
||||
if (await exists(outputDirectory)) {
|
||||
await remove(outputDirectory);
|
||||
}
|
||||
await mkdirp(outputDirectory);
|
||||
|
||||
const sourceFile = jplFiles[0];
|
||||
const destFile = join(outputDirectory, 'plugin.jpl');
|
||||
|
||||
logStatus(`Copying built file from ${sourceFile} to ${destFile}`);
|
||||
await copy(sourceFile, destFile);
|
||||
} else {
|
||||
console.warn('No output directory specified. Not copying built .jpl files.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.log('Build directory', buildDir);
|
||||
await waitForCliInput();
|
||||
throw error;
|
||||
} finally {
|
||||
chdir(originalDirectory);
|
||||
await remove(buildDir);
|
||||
logStatus('Removed build directory');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default buildDefaultPlugins;
|
7
packages/default-plugins/commands/buildAll.ts
Normal file
7
packages/default-plugins/commands/buildAll.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import buildDefaultPlugins from '../buildDefaultPlugins';
|
||||
|
||||
const buildAll = (outputDirectory: string) => {
|
||||
return buildDefaultPlugins(outputDirectory, async () => { });
|
||||
};
|
||||
|
||||
export default buildAll;
|
31
packages/default-plugins/commands/editPatch.ts
Normal file
31
packages/default-plugins/commands/editPatch.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { execCommand } from '@joplin/utils';
|
||||
import waitForCliInput from '../utils/waitForCliInput';
|
||||
import { copy } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import buildDefaultPlugins from '../buildDefaultPlugins';
|
||||
import getPathToPatchFileFor from '../utils/getPathToPatchFileFor';
|
||||
|
||||
const editPatch = async (targetPluginId: string, outputParentDir: string|null) => {
|
||||
let patchedPlugin = false;
|
||||
|
||||
await buildDefaultPlugins(outputParentDir, async (buildDir, pluginId) => {
|
||||
if (pluginId !== targetPluginId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Make changes to', buildDir, 'to create a patch.');
|
||||
await waitForCliInput();
|
||||
await execCommand(['sh', '-c', 'git diff -p > diff.diff']);
|
||||
|
||||
await copy(join(buildDir, './diff.diff'), getPathToPatchFileFor(pluginId));
|
||||
|
||||
patchedPlugin = true;
|
||||
});
|
||||
|
||||
if (!patchedPlugin) {
|
||||
throw new Error(`No default plugin with ID ${targetPluginId} found!`);
|
||||
}
|
||||
};
|
||||
|
||||
export default editPatch;
|
25
packages/default-plugins/package.json
Normal file
25
packages/default-plugins/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@joplin/default-plugins",
|
||||
"version": "2.13.0",
|
||||
"description": "Default plugins bundler",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"tsc": "tsc --project tsconfig.json",
|
||||
"watch": "tsc --watch --preserveWatchOutput --project tsconfig.json",
|
||||
"patch": "ts-node build.ts patch"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/laurent22/joplin.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/yargs": "17.0.31",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/utils": "~2.13",
|
||||
"fs-extra": "11.1.1",
|
||||
"yargs": "17.7.2"
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
diff --git a/src/sevenZip.ts b/src/sevenZip.ts
|
||||
index ef2a527..d98c777 100644
|
||||
--- a/src/sevenZip.ts
|
||||
+++ b/src/sevenZip.ts
|
||||
@@ -1,21 +1,21 @@
|
||||
// https://sevenzip.osdn.jp/chm/cmdline/exit_codes.htm
|
||||
// https://sevenzip.osdn.jp/chm/cmdline/commands/index.htm
|
||||
import * as _7z from "node-7z";
|
||||
-import * as sevenBin from "7zip-bin";
|
||||
-import * as path from "path";
|
||||
import { exec } from "child_process";
|
||||
import joplin from "api";
|
||||
-
|
||||
-export let pathTo7zip = sevenBin.path7za;
|
||||
-
|
||||
-export namespace sevenZip {
|
||||
- export async function updateBinPath() {
|
||||
- pathTo7zip = path.join(
|
||||
- await joplin.plugins.installationDir(),
|
||||
- "7zip-bin",
|
||||
- pathTo7zip
|
||||
- );
|
||||
- }
|
||||
+const sevenBin = joplin.require("7zip-bin");
|
||||
+
|
||||
+ export let pathTo7zip = sevenBin.path7za;
|
||||
+
|
||||
+ export namespace sevenZip {
|
||||
+ export async function updateBinPath() {
|
||||
+ // Not necessary with 7zip required from Joplin
|
||||
+ // pathTo7zip = path.join(
|
||||
+ // await joplin.plugins.installationDir(),
|
||||
+ // "7zip-bin",
|
||||
+ // pathTo7zip
|
||||
+ // );
|
||||
+ }
|
||||
|
||||
export async function setExecutionFlag() {
|
||||
if (process.platform !== "win32") {
|
||||
diff --git a/webpack.config.js b/webpack.config.js
|
||||
index 34a1797..7b2a480 100644
|
||||
--- a/webpack.config.js
|
||||
+++ b/webpack.config.js
|
||||
@@ -200,15 +200,9 @@ const pluginConfig = { ...baseConfig, entry: './src/index.ts',
|
||||
path: distDir,
|
||||
},
|
||||
plugins: [
|
||||
- new CopyPlugin({
|
||||
- patterns: [
|
||||
- {
|
||||
- from: '**/*',
|
||||
- context: path.resolve(__dirname, 'node_modules','7zip-bin'),
|
||||
- to: path.resolve(__dirname, 'dist/7zip-bin/'),
|
||||
- },
|
||||
- ]
|
||||
- }),
|
||||
+ // Removed a CopyPlugin (added by Simple Backup, not necessary when using
|
||||
+ // Joplin's built-in 7zip)
|
||||
+
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
7
packages/default-plugins/pluginRepositories.json
Normal file
7
packages/default-plugins/pluginRepositories.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"io.github.jackgruber.backup": {
|
||||
"cloneUrl": "https://github.com/JackGruber/joplin-plugin-backup.git",
|
||||
"branch": "master",
|
||||
"commit": "021085cc37ed83a91a7950744e462782e27c04a6"
|
||||
}
|
||||
}
|
12
packages/default-plugins/tsconfig.json
Normal file
12
packages/default-plugins/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"plugin-sources/",
|
||||
"plugin-base-repo/"
|
||||
]
|
||||
}
|
9
packages/default-plugins/utils/getPathToPatchFileFor.ts
Normal file
9
packages/default-plugins/utils/getPathToPatchFileFor.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
const getPathToPatchFileFor = (pluginName: string) => {
|
||||
const rootDir = dirname(__dirname);
|
||||
return join(rootDir, 'plugin-patches', `${pluginName}.diff`);
|
||||
};
|
||||
|
||||
export default getPathToPatchFileFor;
|
37
packages/default-plugins/utils/readRepositoryJson.ts
Normal file
37
packages/default-plugins/utils/readRepositoryJson.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { readFile } from 'fs-extra';
|
||||
|
||||
export interface RepositoryData {
|
||||
cloneUrl: string;
|
||||
branch: string;
|
||||
commit: string;
|
||||
}
|
||||
|
||||
export interface AllRepositoryData {
|
||||
[pluginId: string]: RepositoryData;
|
||||
}
|
||||
|
||||
const readRepositoryJson = async (repositoryDataFilepath: string): Promise<AllRepositoryData> => {
|
||||
const fileContent = await readFile(repositoryDataFilepath, 'utf8');
|
||||
const parsedJson = JSON.parse(fileContent);
|
||||
|
||||
// Validate
|
||||
for (const pluginId in parsedJson) {
|
||||
if (typeof parsedJson[pluginId] !== 'object') {
|
||||
throw new Error('pluginRepositories should map from plugin IDs to objects.');
|
||||
}
|
||||
|
||||
const assertPropertyIsString = (propertyName: string) => {
|
||||
if (typeof parsedJson[pluginId][propertyName] !== 'string') {
|
||||
throw new Error(`Plugin ${pluginId} should have field '${propertyName}' of type string.`);
|
||||
}
|
||||
};
|
||||
|
||||
assertPropertyIsString('cloneUrl');
|
||||
assertPropertyIsString('branch');
|
||||
assertPropertyIsString('commit');
|
||||
}
|
||||
|
||||
return parsedJson;
|
||||
};
|
||||
|
||||
export default readRepositoryJson;
|
23
packages/default-plugins/utils/waitForCliInput.ts
Normal file
23
packages/default-plugins/utils/waitForCliInput.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
const readline = require('readline/promises');
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
let readlineInterface: any = null;
|
||||
const waitForCliInput = async () => {
|
||||
readlineInterface ??= readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
if (process.stdin.isTTY) {
|
||||
const green = '\x1b[92m';
|
||||
const reset = '\x1b[0m';
|
||||
await readlineInterface.question(`${green}[Press enter to continue]${reset}`);
|
||||
|
||||
console.log('Continuing...');
|
||||
} else {
|
||||
console.warn('Input is not from a TTY -- not waiting for input.');
|
||||
}
|
||||
};
|
||||
|
||||
export default waitForCliInput;
|
Reference in New Issue
Block a user