Merge pull request #3579 from thelounge/xpaw/watch-packages

Automatically load new packages (fs.watch package.json)
This commit is contained in:
Pavel Djundik 2019-12-14 21:33:56 +02:00 committed by GitHub
commit d99b6d0a17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 68 deletions

View File

@ -2,6 +2,7 @@
const log = require("../log"); const log = require("../log");
const fs = require("fs"); const fs = require("fs");
const fsextra = require("fs-extra");
const path = require("path"); const path = require("path");
const colors = require("chalk"); const colors = require("chalk");
const program = require("commander"); const program = require("commander");
@ -36,6 +37,9 @@ try {
// fs.statSync will throw if config.js does not exist (e.g. first run) // fs.statSync will throw if config.js does not exist (e.g. first run)
} }
// Create packages/package.json
createPackagesFolder();
// Merge config key-values passed as CLI options into the main config // Merge config key-values passed as CLI options into the main config
Helper.mergeConfig(Helper.config, program.config); Helper.mergeConfig(Helper.config, program.config);
@ -62,6 +66,31 @@ if (program.rawArgs.length < 3) {
program.help(); program.help();
} }
function createPackagesFolder() {
const packagesPath = Helper.getPackagesPath();
const packagesConfig = path.join(packagesPath, "package.json");
// Create node_modules folder, otherwise yarn will start walking upwards to find one
fsextra.ensureDirSync(path.join(packagesPath, "node_modules"));
// Create package.json with private set to true, if it doesn't exist already
if (!fs.existsSync(packagesConfig)) {
fs.writeFileSync(
packagesConfig,
JSON.stringify(
{
private: true,
description:
"Packages for The Lounge. All packages in node_modules directory will be automatically loaded.",
dependencies: {},
},
null,
"\t"
)
);
}
}
function verifyFileOwner() { function verifyFileOwner() {
if (!process.getuid) { if (!process.getuid) {
return; return;

View File

@ -12,8 +12,6 @@ program
.on("--help", Utils.extraHelp) .on("--help", Utils.extraHelp)
.action(function(packageName) { .action(function(packageName) {
const fs = require("fs"); const fs = require("fs");
const fsextra = require("fs-extra");
const path = require("path");
const packageJson = require("package-json"); const packageJson = require("package-json");
if (!fs.existsSync(Helper.getConfigPath())) { if (!fs.existsSync(Helper.getConfigPath())) {
@ -44,28 +42,6 @@ program
log.info(`Installing ${colors.green(json.name + " v" + json.version)}...`); log.info(`Installing ${colors.green(json.name + " v" + json.version)}...`);
const packagesPath = Helper.getPackagesPath();
const packagesConfig = path.join(packagesPath, "package.json");
// Create node_modules folder, otherwise yarn will start walking upwards to find one
fsextra.ensureDirSync(path.join(packagesPath, "node_modules"));
// Create package.json with private set to true, if it doesn't exist already
if (!fs.existsSync(packagesConfig)) {
fs.writeFileSync(
packagesConfig,
JSON.stringify(
{
private: true,
description:
"Packages for The Lounge. All packages in node_modules directory will be automatically loaded.",
},
null,
"\t"
)
);
}
return Utils.executeYarnCommand("add", "--exact", `${json.name}@${json.version}`) return Utils.executeYarnCommand("add", "--exact", `${json.name}@${json.version}`)
.then(() => { .then(() => {
log.info( log.info(

View File

@ -1,5 +1,6 @@
"use strict"; "use strict";
const _ = require("lodash");
const log = require("../../log"); const log = require("../../log");
const colors = require("chalk"); const colors = require("chalk");
const path = require("path"); const path = require("path");
@ -19,6 +20,8 @@ const cache = {
outdated: undefined, outdated: undefined,
}; };
let experimentalWarningPrinted = false;
module.exports = { module.exports = {
getFiles, getFiles,
getStylesheets, getStylesheets,
@ -66,25 +69,25 @@ function getPackage(name) {
return packageMap.get(name); return packageMap.get(name);
} }
function loadPackages() { function getEnabledPackages(packageJson) {
const packageJson = path.join(Helper.getPackagesPath(), "package.json");
let packages;
let anyPlugins = false;
try { try {
packages = Object.keys(require(packageJson).dependencies); const json = JSON.parse(fs.readFileSync(packageJson, "utf-8"));
return Object.keys(json.dependencies);
} catch (e) { } catch (e) {
packages = []; log.error(`Failed to read packages/package.json: ${colors.red(e)}`);
} }
packages.forEach((packageName) => { return [];
}
function loadPackage(packageName) {
let packageInfo; let packageInfo;
let packageFile; let packageFile;
try { try {
const packagePath = Helper.getPackageModulePath(packageName); const packagePath = Helper.getPackageModulePath(packageName);
packageInfo = require(path.join(packagePath, "package.json")); packageInfo = JSON.parse(fs.readFileSync(path.join(packagePath, "package.json"), "utf-8"));
if (!packageInfo.thelounge) { if (!packageInfo.thelounge) {
throw "'thelounge' is not present in package.json"; throw "'thelounge' is not present in package.json";
@ -110,8 +113,6 @@ function loadPackages() {
if (packageInfo.files) { if (packageInfo.files) {
packageInfo.files.forEach((file) => addFile(packageName, file)); packageInfo.files.forEach((file) => addFile(packageName, file));
} }
} else {
anyPlugins = true;
} }
if (packageFile.onServerStart) { if (packageFile.onServerStart) {
@ -119,15 +120,50 @@ function loadPackages() {
} }
log.info(`Package ${colors.bold(packageName)} ${colors.green("v" + version)} loaded`); log.info(`Package ${colors.bold(packageName)} ${colors.green("v" + version)} loaded`);
});
if (anyPlugins) { if (packageInfo.type !== "theme" && !experimentalWarningPrinted) {
experimentalWarningPrinted = true;
log.info( log.info(
"There are packages using the experimental plugin API. Be aware that this API is not yet stable and may change in future The Lounge releases." "There are packages using the experimental plugin API. " +
"Be aware that this API is not yet stable and may change in future The Lounge releases."
); );
} }
} }
function loadPackages() {
const packageJson = path.join(Helper.getPackagesPath(), "package.json");
const packages = getEnabledPackages(packageJson);
packages.forEach(loadPackage);
watchPackages(packageJson);
}
function watchPackages(packageJson) {
fs.watch(
packageJson,
{
persistent: false,
},
_.debounce(
() => {
const updated = getEnabledPackages(packageJson);
for (const packageName of updated) {
if (packageMap.has(packageName)) {
continue;
}
loadPackage(packageName);
}
},
1000,
{maxWait: 10000}
)
);
}
async function outdated(cacheTimeout = TIME_TO_LIVE) { async function outdated(cacheTimeout = TIME_TO_LIVE) {
if (cache.outdated !== undefined) { if (cache.outdated !== undefined) {
return cache.outdated; return cache.outdated;