1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00
joplin/packages/tools/tool-utils.js

355 lines
8.6 KiB
JavaScript
Raw Normal View History

const fetch = require('node-fetch');
const fs = require('fs-extra');
2020-11-06 20:45:45 +02:00
const execa = require('execa');
const { execSync } = require('child_process');
2017-12-04 20:16:14 +02:00
const toolUtils = {};
toolUtils.execCommand = function(command) {
const exec = require('child_process').exec;
2017-12-04 20:16:14 +02:00
return new Promise((resolve, reject) => {
2019-10-13 23:19:15 +02:00
exec(command, (error, stdout) => {
2017-12-04 20:16:14 +02:00
if (error) {
if (error.signal == 'SIGTERM') {
resolve('Process was killed');
} else {
reject(error);
}
} else {
resolve(stdout.trim());
}
});
});
};
2020-11-06 20:45:45 +02:00
function quotePath(path) {
if (!path) return '';
if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path;
path = path.replace(/"/, '\\"');
return `"${path}"`;
}
function commandToString(commandName, args = []) {
const output = [quotePath(commandName)];
for (const arg of args) {
output.push(quotePath(arg));
}
return output.join(' ');
}
toolUtils.execCommandVerbose = function(commandName, args = []) {
console.info(`> ${commandToString(commandName, args)}`);
const promise = execa(commandName, args);
promise.stdout.pipe(process.stdout);
return promise;
};
toolUtils.execCommandWithPipes = function(executable, args) {
const spawn = require('child_process').spawn;
return new Promise((resolve, reject) => {
const child = spawn(executable, args, { stdio: 'inherit' });
child.on('error', (error) => {
reject(error);
});
child.on('close', (code) => {
if (code !== 0) {
reject(`Ended with code ${code}`);
} else {
resolve();
}
});
2017-12-04 20:16:14 +02:00
});
};
2017-12-04 20:16:14 +02:00
2020-11-06 20:45:45 +02:00
toolUtils.toSystemSlashes = function(path) {
const os = process.platform;
if (os === 'win32') return path.replace(/\//g, '\\');
return path.replace(/\\/g, '/');
};
toolUtils.deleteLink = async function(path) {
if (toolUtils.isWindows()) {
try {
execSync(`rmdir "${toolUtils.toSystemSlashes(path)}"`, { stdio: 'pipe' });
} catch (error) {
// console.info('Error: ' + error.message);
}
} else {
try {
fs.unlinkSync(toolUtils.toSystemSlashes(path));
} catch (error) {
// ignore
}
}
};
2020-11-05 19:40:13 +02:00
toolUtils.credentialDir = async function() {
const username = require('os').userInfo().username;
const toTry = [
`c:/Users/${username}/joplin-credentials`,
`/mnt/c/Users/${username}/joplin-credentials`,
`/home/${username}/joplin-credentials`,
`/Users/${username}/joplin-credentials`,
];
for (const dirPath of toTry) {
if (await fs.exists(dirPath)) return dirPath;
}
throw new Error(`Could not find credential directory in any of these paths: ${JSON.stringify(toTry)}`);
};
2020-11-05 19:44:19 +02:00
// Returns the project root dir
toolUtils.rootDir = require('path').dirname(require('path').dirname(__dirname));
2020-11-05 19:40:13 +02:00
toolUtils.credentialFile = async function(filename) {
const rootDir = await toolUtils.credentialDir();
const output = `${rootDir}/${filename}`;
if (!(await fs.exists(output))) throw new Error(`No such file: ${output}`);
return output;
};
toolUtils.readCredentialFile = async function(filename) {
const filePath = await toolUtils.credentialFile(filename);
const r = await fs.readFile(filePath);
return r.toString();
};
2017-12-04 20:16:14 +02:00
toolUtils.downloadFile = function(url, targetPath) {
const https = require('https');
const fs = require('fs');
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(targetPath);
https.get(url, function(response) {
2019-09-19 23:51:18 +02:00
if (response.statusCode !== 200) reject(new Error(`HTTP error ${response.statusCode}`));
2017-12-04 20:16:14 +02:00
response.pipe(file);
file.on('finish', function() {
2019-10-09 21:35:13 +02:00
// file.close();
2017-12-04 20:16:14 +02:00
resolve();
});
}).on('error', (error) => {
reject(error);
});
});
};
2017-12-04 20:16:14 +02:00
toolUtils.fileSha256 = function(filePath) {
return new Promise((resolve, reject) => {
const crypto = require('crypto');
const fs = require('fs');
const algo = 'sha256';
const shasum = crypto.createHash(algo);
const s = fs.ReadStream(filePath);
s.on('data', function(d) { shasum.update(d); });
s.on('end', function() {
const d = shasum.digest('hex');
resolve(d);
});
s.on('error', function(error) {
reject(error);
});
});
};
2017-12-04 20:16:14 +02:00
toolUtils.unlinkForce = async function(filePath) {
const fs = require('fs-extra');
try {
await fs.unlink(filePath);
} catch (error) {
if (error.code === 'ENOENT') return;
throw error;
}
};
2017-12-04 20:16:14 +02:00
toolUtils.fileExists = async function(filePath) {
2018-10-13 12:09:03 +02:00
const fs = require('fs-extra');
2017-12-04 20:16:14 +02:00
return new Promise((resolve, reject) => {
fs.stat(filePath, function(err) {
2017-12-04 20:16:14 +02:00
if (err == null) {
resolve(true);
2019-10-09 21:35:13 +02:00
} else if (err.code == 'ENOENT') {
2017-12-04 20:16:14 +02:00
resolve(false);
} else {
reject(err);
}
});
});
};
2017-12-04 20:16:14 +02:00
async function loadGitHubUsernameCache() {
const path = `${__dirname}/github_username_cache.json`;
if (await fs.exists(path)) {
const jsonString = await fs.readFile(path);
return JSON.parse(jsonString);
}
return {};
}
async function saveGitHubUsernameCache(cache) {
const path = `${__dirname}/github_username_cache.json`;
await fs.writeFile(path, JSON.stringify(cache));
}
2020-01-25 00:43:55 +02:00
toolUtils.githubUsername = async function(email, name) {
const cache = await loadGitHubUsernameCache();
2020-01-25 00:43:55 +02:00
const cacheKey = `${email}:${name}`;
if (cacheKey in cache) return cache[cacheKey];
let output = null;
const oauthToken = await toolUtils.githubOauthToken();
2020-01-25 00:43:55 +02:00
const urlsToTry = [
`https://api.github.com/search/users?q=${encodeURI(email)}+in:email`,
`https://api.github.com/search/users?q=user:${encodeURI(name)}`,
];
for (const url of urlsToTry) {
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `token ${oauthToken}`,
},
});
const responseText = await response.text();
2020-01-25 00:43:55 +02:00
if (!response.ok) continue;
const responseJson = JSON.parse(responseText);
2020-01-25 00:43:55 +02:00
if (!responseJson || !responseJson.items || responseJson.items.length !== 1) continue;
output = responseJson.items[0].login;
break;
}
2020-01-25 00:43:55 +02:00
cache[cacheKey] = output;
await saveGitHubUsernameCache(cache);
2020-01-25 00:43:55 +02:00
return output;
};
toolUtils.patreonOauthToken = async function() {
2020-11-05 19:40:13 +02:00
return toolUtils.readCredentialFile('patreon_oauth_token.txt');
};
toolUtils.githubOauthToken = async function() {
2020-11-05 19:40:13 +02:00
return toolUtils.readCredentialFile('github_oauth_token.txt');
};
2019-01-12 00:07:23 +02:00
toolUtils.githubRelease = async function(project, tagName, options = null) {
options = Object.assign({}, {
isDraft: false,
isPreRelease: false,
}, options);
2018-02-05 19:27:38 +02:00
const oauthToken = await toolUtils.githubOauthToken();
2019-09-19 23:51:18 +02:00
const response = await fetch(`https://api.github.com/repos/laurent22/${project}/releases`, {
method: 'POST',
body: JSON.stringify({
tag_name: tagName,
name: tagName,
2019-01-12 00:07:23 +02:00
draft: options.isDraft,
prerelease: options.isPreRelease,
}),
headers: {
'Content-Type': 'application/json',
2019-09-19 23:51:18 +02:00
'Authorization': `token ${oauthToken}`,
},
});
const responseText = await response.text();
2019-09-19 23:51:18 +02:00
if (!response.ok) throw new Error(`Cannot create GitHub release: ${responseText}`);
const responseJson = JSON.parse(responseText);
2019-09-19 23:51:18 +02:00
if (!responseJson.url) throw new Error(`No URL for release: ${responseText}`);
return responseJson;
};
toolUtils.readline = question => {
return new Promise((resolve) => {
2019-06-15 19:58:09 +02:00
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
2019-06-15 19:58:09 +02:00
});
rl.question(`${question} `, answer => {
2019-06-15 19:58:09 +02:00
resolve(answer);
rl.close();
});
});
};
2019-06-15 19:58:09 +02:00
toolUtils.isLinux = () => {
return process && process.platform === 'linux';
};
toolUtils.isWindows = () => {
return process && process.platform === 'win32';
};
toolUtils.isMac = () => {
return process && process.platform === 'darwin';
};
2019-09-30 00:11:36 +02:00
toolUtils.insertContentIntoFile = async function(filePath, markerOpen, markerClose, contentToInsert) {
2019-07-18 19:36:29 +02:00
const fs = require('fs-extra');
let content = await fs.readFile(filePath, 'utf-8');
// [^]* matches any character including new lines
2019-09-19 23:51:18 +02:00
const regex = new RegExp(`${markerOpen}[^]*?${markerClose}`);
2019-07-18 19:36:29 +02:00
content = content.replace(regex, markerOpen + contentToInsert + markerClose);
await fs.writeFile(filePath, content);
};
2019-07-18 19:36:29 +02:00
2020-11-05 18:58:23 +02:00
toolUtils.dirname = (path) => {
if (!path) throw new Error('Path is empty');
const s = path.split(/\/|\\/);
s.pop();
return s.join('/');
};
toolUtils.basename = (path) => {
if (!path) throw new Error('Path is empty');
const s = path.split(/\/|\\/);
return s[s.length - 1];
};
toolUtils.filename = (path, includeDir = false) => {
if (!path) throw new Error('Path is empty');
const output = includeDir ? path : toolUtils.basename(path);
if (output.indexOf('.') < 0) return output;
const splitted = output.split('.');
splitted.pop();
return splitted.join('.');
};
toolUtils.fileExtension = (path) => {
if (!path) throw new Error('Path is empty');
const output = path.split('.');
if (output.length <= 1) return '';
return output[output.length - 1];
};
module.exports = toolUtils;