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 fs = require("fs");
const fsextra = require("fs-extra");
const path = require("path");
const colors = require("chalk");
const program = require("commander");
@ -36,6 +37,9 @@ try {
// 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
Helper.mergeConfig(Helper.config, program.config);
@ -62,6 +66,31 @@ if (program.rawArgs.length < 3) {
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() {
if (!process.getuid) {
return;

View file

@ -12,8 +12,6 @@ program
.on("--help", Utils.extraHelp)
.action(function(packageName) {
const fs = require("fs");
const fsextra = require("fs-extra");
const path = require("path");
const packageJson = require("package-json");
if (!fs.existsSync(Helper.getConfigPath())) {
@ -44,28 +42,6 @@ program
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}`)
.then(() => {
log.info(

View file

@ -1,5 +1,6 @@
"use strict";
const _ = require("lodash");
const log = require("../../log");
const colors = require("chalk");
const path = require("path");
@ -19,6 +20,8 @@ const cache = {
outdated: undefined,
};
let experimentalWarningPrinted = false;
module.exports = {
getFiles,
getStylesheets,
@ -66,68 +69,101 @@ function getPackage(name) {
return packageMap.get(name);
}
function loadPackages() {
const packageJson = path.join(Helper.getPackagesPath(), "package.json");
let packages;
let anyPlugins = false;
function getEnabledPackages(packageJson) {
try {
const json = JSON.parse(fs.readFileSync(packageJson, "utf-8"));
return Object.keys(json.dependencies);
} catch (e) {
log.error(`Failed to read packages/package.json: ${colors.red(e)}`);
}
return [];
}
function loadPackage(packageName) {
let packageInfo;
let packageFile;
try {
packages = Object.keys(require(packageJson).dependencies);
const packagePath = Helper.getPackageModulePath(packageName);
packageInfo = JSON.parse(fs.readFileSync(path.join(packagePath, "package.json"), "utf-8"));
if (!packageInfo.thelounge) {
throw "'thelounge' is not present in package.json";
}
packageFile = require(packagePath);
} catch (e) {
packages = [];
log.error(`Package ${colors.bold(packageName)} could not be loaded: ${colors.red(e)}`);
log.debug(e.stack);
return;
}
packages.forEach((packageName) => {
let packageInfo;
let packageFile;
const version = packageInfo.version;
packageInfo = packageInfo.thelounge;
packageInfo.packageName = packageName;
packageInfo.version = version;
try {
const packagePath = Helper.getPackageModulePath(packageName);
packageMap.set(packageName, packageFile);
packageInfo = require(path.join(packagePath, "package.json"));
if (packageInfo.type === "theme") {
themes.addTheme(packageName, packageInfo);
if (!packageInfo.thelounge) {
throw "'thelounge' is not present in package.json";
}
packageFile = require(packagePath);
} catch (e) {
log.error(`Package ${colors.bold(packageName)} could not be loaded: ${colors.red(e)}`);
log.debug(e.stack);
return;
if (packageInfo.files) {
packageInfo.files.forEach((file) => addFile(packageName, file));
}
}
const version = packageInfo.version;
packageInfo = packageInfo.thelounge;
packageInfo.packageName = packageName;
packageInfo.version = version;
if (packageFile.onServerStart) {
packageFile.onServerStart(packageApis(packageInfo));
}
packageMap.set(packageName, packageFile);
log.info(`Package ${colors.bold(packageName)} ${colors.green("v" + version)} loaded`);
if (packageInfo.type === "theme") {
themes.addTheme(packageName, packageInfo);
if (packageInfo.type !== "theme" && !experimentalWarningPrinted) {
experimentalWarningPrinted = true;
if (packageInfo.files) {
packageInfo.files.forEach((file) => addFile(packageName, file));
}
} else {
anyPlugins = true;
}
if (packageFile.onServerStart) {
packageFile.onServerStart(packageApis(packageInfo));
}
log.info(`Package ${colors.bold(packageName)} ${colors.green("v" + version)} loaded`);
});
if (anyPlugins) {
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) {
if (cache.outdated !== undefined) {
return cache.outdated;