Skip to content

Commit

Permalink
feat: host user specific configuration externally
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed Nov 9, 2018
1 parent 36b65af commit 9fee809
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 96 deletions.
18 changes: 16 additions & 2 deletions bin/dev-package-install.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,22 @@ if (argv.v || argv.version) {
const [packageName] = argv._;

if (!packageName) {
process.stderr.write(`Provide package name to setup\n\n${ usage }`);
process.stderr.write(`Provide package name to install\n\n${ usage }`);
process.exit(1);
}

require("..")(process.cwd(), packageName);
const clc = require("cli-color")
, DevPackageInstallError = require("../lib/dev-package-install-error")
, installPackage = require("../lib/install-package")
, resolveUserConfiguration = require("../lib/resolve-user-configuration");

resolveUserConfiguration()
.then(configuration => installPackage(packageName, configuration))
.catch(error => {
if (error instanceof DevPackageInstallError) {
process.stdout.write(`\n${ clc.red(error.message) }\n`);
process.exit(1);
return;
}
throw error;
});
8 changes: 5 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"use strict";

const { resolve } = require("path")
, setupPackage = require("./lib/setup-package");
const ensureString = require("es5-ext/object/validate-stringifiable-value")
, ensureConfiguration = require("./lib/ensure-configuration")
, installPackage = require("./lib/install-package");

module.exports = (packagesPath, packageName) => setupPackage(resolve(packagesPath), packageName);
module.exports = (packageName, configuration) =>
installPackage(ensureString(packageName), ensureConfiguration(configuration));
3 changes: 3 additions & 0 deletions lib/dev-package-install-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";

module.exports = class DevPackageInstallError extends Error {};
37 changes: 37 additions & 0 deletions lib/ensure-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use strict";

const ensureObject = require("es5-ext/object/valid-object")
, ensurePlainFunction = require("es5-ext/object/ensure-plain-function")
, ensureString = require("es5-ext/object/validate-stringifiable-value")
, { resolve } = require("path")
, { homedir } = require("os")
, log = require("log4").get("dev-package-install:configuration").info;

module.exports = userConfiguration => {
log.debug("user configuration: %O", userConfiguration);

const configuration = {};

configuration.packagesPath = userConfiguration.packagesPath
? resolve(ensureString(userConfiguration.packagesPath))
: resolve(homedir(), "npm-packages");
log("packages path: %s", configuration.packagesPath);

ensureObject(userConfiguration.packagesMeta);
const packagesMeta = (configuration.packagesMeta = Object.create(null));
for (const [packageName, userPackageMeta] of Object.entries(userConfiguration.packagesMeta)) {
ensureObject(userPackageMeta);
const packageMeta = (packagesMeta[packageName] = {});
packageMeta.repoUrl = ensureString(userPackageMeta.repoUrl);
log.get("package-meta")("recognize %s at %s", packageName, packageMeta.repoUrl);
}

const hooks = (configuration.hooks = {});
if (!userConfiguration.hooks) return configuration;
const userHooks = ensureObject(userConfiguration.hooks);
if (userHooks.afterPackageInstall) {
hooks.afterPackageInstall = ensurePlainFunction(userHooks.afterPackageInstall);
log.get("hooks")("recognize %s", "afterPackageInstall");
}
return configuration;
};
39 changes: 19 additions & 20 deletions lib/setup-package.js → lib/install-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@

const { resolve } = require("path")
, rmdir = require("fs2/rmdir")
, logger = require("log4").get("setup-own-package")
, isOwnPackage = require("./is-own-package")
, logger = require("log4").get("dev-package-install")
, isPackageLinked = require("./is-package-linked")
, runProgram = require("./run-program")
, setupPrettier = require("./setup-prettier")
, setupRepository = require("./setup-repository")
, setupNpmLink = require("./setup-npm-link");

const exceptionsMap = new Map([["webmake", "modules-webmake"], ["next", "node-ext"]]);

const ongoingMap = new Map();
const done = new Set();

const setupDependencies = async (packagesPath, packageName) => {
const setupDependencies = async (packageName, { packagesPath, packagesMeta, hooks }) => {
const packagePath = resolve(packagesPath, packageName);
const packageMeta = require(resolve(packagePath, "package.json"));
const packagePkgJson = require(resolve(packagePath, "package.json"));
const dependencies = new Set(
Object.keys(packageMeta.dependencies || {}).concat(
Object.keys(packageMeta.devDependencies || {})
Object.keys(packagePkgJson.dependencies || {}).concat(
Object.keys(packagePkgJson.devDependencies || {})
)
);
dependencies.delete(packageName);
Expand All @@ -33,15 +29,15 @@ const setupDependencies = async (packagesPath, packageName) => {
.get(dependencyName)
.push(() => setupNpmLink(packagePath, dependencyName));
continue;
} else if (exceptionsMap.has(dependencyName) || await isOwnPackage(dependencyName)) {
await module.exports(packagesPath, dependencyName);
} else if (packagesMeta[dependencyName]) {
await module.exports(dependencyName, { packagesPath, packagesMeta, hooks });
}
}
await setupNpmLink(packagePath, dependencyName);
}

// Eventual optional dependencies
for (const dependencyName of Object.keys(packageMeta.optionalDependencies || {})) {
for (const dependencyName of Object.keys(packagePkgJson.optionalDependencies || {})) {
if (dependencyName === packageName) continue;
if (dependencies.has(dependencyName)) continue;
try { await setupNpmLink(packagePath, dependencyName); }
Expand All @@ -54,17 +50,15 @@ const setupDependencies = async (packagesPath, packageName) => {
}
};

module.exports = async (packagesPath, packageName) => {
module.exports = async (packageName, { packagesPath, packagesMeta, hooks }) => {
const packagePath = resolve(packagesPath, packageName);

logger.notice("setup package %s", packageName);
const pendingJobs = [];
ongoingMap.set(packageName, pendingJobs);

// Setup repository
await setupRepository(
packagePath, `[email protected]:medikoo/${ exceptionsMap.get(packageName) || packageName }.git`
);
await setupRepository(packagePath, packagesMeta[packageName].repoUrl);

// Cleanup eventual npm crashes
await rmdir(resolve(packagePath, "node_modules/.staging"), {
Expand All @@ -74,19 +68,24 @@ module.exports = async (packagesPath, packageName) => {
});

// Setup dependencies
await setupDependencies(packagesPath, packageName);
await setupDependencies(packageName, { packagesPath, packagesMeta, hooks });

// Link package
if (!await isPackageLinked(packageName)) {
if (!(await isPackageLinked(packageName))) {
logger.notice("link %s", packageName);
await runProgram("npm", ["link"], {
cwd: packagePath,
logger: logger.levelRoot.get("npm:link")
});
}

// Setup prettier link
await setupPrettier(packagesPath, packagePath);
// Run eventual afterPackageInstall hooks
if (hooks.afterPackageInstall) {
await hooks.afterPackageInstall(packageName, {
packagesPath,
packageMeta: packagesMeta[packageName]
});
}

// Done
logger.notice("done %s", packageName);
Expand Down
24 changes: 0 additions & 24 deletions lib/is-own-package.js

This file was deleted.

2 changes: 1 addition & 1 deletion lib/is-package-linked.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

const logger = require("log4").get("setup-own-package")
const logger = require("log4").get("dev-package-install")
, { resolve } = require("path")
, memoize = require("memoizee")
, isSymbolicLink = require("./is-symbolic-link")
Expand Down
24 changes: 24 additions & 0 deletions lib/resolve-user-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use strict";

const { resolve } = require("path")
, { homedir } = require("os")
, isModuleNotFoundError = require("cjs-module/is-module-not-found-error")
, DevPackageInstallError = require("./dev-package-install-error")
, ensureConfiguration = require("./ensure-configuration");

const configurationPath = resolve(homedir(), ".dev-package-install");

const resolveConfigurationModule = () => {
try {
return require(configurationPath);
} catch (error) {
if (isModuleNotFoundError(error, configurationPath)) {
throw new DevPackageInstallError(
"Configuration not provided at ~/.dev-package-install"
);
}
throw error;
}
};

module.exports = async () => ensureConfiguration(await resolveConfigurationModule());
8 changes: 6 additions & 2 deletions lib/run-program.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ module.exports = (command, args, options) => {
const { child } = promise;

if (logger) {
child.stdout.pipe(split()).on("data", data => logger.info(String(data)));
child.stderr.pipe(split()).on("data", data => logger.notice(String(data)));
child.stdout
.pipe(split(/\r?\n/u, null, { trailing: false }))
.on("data", data => logger.info(String(data)));
child.stderr
.pipe(split(/\r?\n/u, null, { trailing: false }))
.on("data", data => logger.notice(String(data)));
}
return promise;
};
4 changes: 2 additions & 2 deletions lib/setup-npm-link.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";

const { basename, resolve } = require("path")
, logger = require("log4").get("setup-own-package")
, logger = require("log4").get("dev-package-install")
, rm = require("fs2/rm")
, isSymbolicLink = require("./is-symbolic-link")
, runProgram = require("./run-program");
Expand All @@ -10,7 +10,7 @@ module.exports = async (packagePath, dependencyName) => {
const dependencyLinkPath = resolve(packagePath, "node_modules", dependencyName);
if (await isSymbolicLink(dependencyLinkPath)) return;
logger.notice("link %s in %s", dependencyName, basename(packagePath));
await rm(dependencyLinkPath);
await rm(dependencyLinkPath, { loose: true });
await runProgram("npm", ["link", dependencyName], {
cwd: packagePath,
logger: logger.levelRoot.get("npm:link")
Expand Down
31 changes: 0 additions & 31 deletions lib/setup-prettier.js

This file was deleted.

10 changes: 5 additions & 5 deletions lib/setup-repository.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

const logger = require("log4").get("setup-own-package")
const logger = require("log4").get("dev-package-install")
, isDirectory = require("./is-directory")
, runProgram = require("./run-program");

Expand All @@ -12,10 +12,10 @@ module.exports = async (repoPath, repoUrl) => {

// Update
logger.notice("update repository %s", repoPath);
await runProgram("git", ["pull"], {
cwd: repoPath,
logger: logger.levelRoot.get("git:pull")
});
// await runProgram("git", ["pull"], {
// cwd: repoPath,
// logger: logger.levelRoot.get("git:pull")
// });
return;
}
logger.notice("clone repository %s from %s", repoPath, repoUrl);
Expand Down
4 changes: 2 additions & 2 deletions lib/setup-symbolic-link.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use strict";

const logger = require("log4").get("setup-own-package")
const logger = require("log4").get("dev-package-install")
, rm = require("fs2/rm")
, symlink = require("fs2/symlink");

module.exports = async (target, path) => {
await rm(path);
await rm(path, { loose: true });
logger.info("create symlink of %s at %s", target, path);
await symlink(target, path, { type: "dir", intermediate: true });
};
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
"dependencies": {
"child-process-es6-promise": "^1.2",
"cjs-module": "^1.4",
"deferred": "^0.7.9",
"cli-color": "^1.3",
"xdeferred": "^0.7.9",
"es5-ext": "^0.10.46",
"fs2": "^0.2.10",
"log4": "^3.0.1",
"log4-nodejs": "^2.3.1",
"memoizee": "^0.4.14",
"minimist": "^1.2",
"split": "^1.0.1",
"@octokit/rest": "^15.11.1"
"split": "^1.0.1"
},
"devDependencies": {
"eslint": "^5.5",
Expand All @@ -30,7 +30,7 @@
},
"overrides": [
{
"files": "lib/setup-package.js",
"files": "lib/install-package.js",
"rules": {
"no-await-in-loop": "off"
}
Expand Down

0 comments on commit 9fee809

Please sign in to comment.