Skip to content

Commit

Permalink
feat: new version
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed Nov 9, 2018
1 parent 3d08c64 commit 8471227
Show file tree
Hide file tree
Showing 17 changed files with 400 additions and 157 deletions.
42 changes: 42 additions & 0 deletions bin/setup-own-package
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env node

"use strict";

Error.stackTraceLimit = Infinity;

process.on("unhandledRejection", reason => { throw reason; });

require("log4-nodejs")();

const meta = require("../package")
, argv = require("minimist")(process.argv.slice(2));

const usage = `setup-package v${ meta.version } - Setup package
Usage: setup-package package-name
Options:
--version, -v Display version
--help, -h Show this message
`;

if (argv.h || argv.help) {
process.stdout.write(usage);
return;
}

if (argv.v || argv.version) {
process.stdout.write(`${ meta.version }\n`);
return;
}

const [packageName] = argv._;

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

require("..")(process.cwd(), packageName);
79 changes: 3 additions & 76 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,6 @@
"use strict";

const partial = require("es5-ext/function/#/partial")
, startsWith = require("es5-ext/string/#/starts-with")
, deferred = require("deferred")
, exec = require("exec-batch/exec")
, lstat = require("fs2/lstat")
, mkdir = require("fs2/mkdir")
, symlink = require("fs2/symlink")
, { resolve } = require("path")
, packages = require("./packages");
const { resolve } = require("path")
, setupPackage = require("./lib/setup-package");

const { keys } = Object
, root = process.cwd()
, dir = resolve(root, "modules")
, done = Object.create(null)
, done2 = Object.create(null);

require("events").EventEmitter.defaultMaxListeners = Infinity;

const setup = function (at, name) {
if (done2[`${ at }|${ name }`]) return null;
done2[`${ at }|${ name }`] = true;
if (!packages[name]) return exec(`npm install ${ name }`, { cwd: at });
const path = resolve(at, "node_modules", name);
return lstat(resolve(path))(
stats => {
if (!stats.isSymbolicLink()) {
throw new Error(`Path '${ path }' is not a symbolic link`);
}
},
err => {
if (err.code !== "ENOENT") throw err;
return deferred(
mkdir(resolve(at, "node_modules"), { intermediate: true }), setupGit(name)
)(() => symlink(resolve(dir, name), resolve(at, "node_modules", name)));
}
);
};

const setupGit = function (name) {
if (done[name]) return null;
done[name] = true;
return lstat(resolve(dir, name))(
stats => {
if (!stats.isDirectory()) {
throw new Error(`Path '${ name }' is not adirectory`);
}
console.log("Do pull of", name);
return exec("git pull", { cwd: resolve(dir, name) });
},
err => {
let gitName, repoName;
if (err.code !== "ENOENT") throw err;
gitName = packages[name] === true ? name : packages[name];
repoName = startsWith.call(gitName, "git@")
? gitName
: `[email protected]:medikoo/${ gitName }.git`;
return exec(`git clone ${ repoName } ${ name }`, { cwd: dir }).aside(null, err => {
console.log(`Repository '${ repoName }' not found`);
});
}
)(() => {
const dRequire = require
, conf = dRequire(resolve(dir, name, "package.json"))
, path = resolve(dir, name)
, lSetup = deferred.gate(partial.call(setup, path), 1);

return deferred(
deferred.map(keys(conf.dependencies || {}) || [], lSetup),
deferred.map(keys(conf.devDependencies || {}) || [], lSetup),
deferred.map(keys(conf.peerDependencies || {}) || [], lSetup)
);
});
};

mkdir(dir, { intermediate: true })(() =>
deferred.map(keys(packages), deferred.gate(setupGit, 1))
).done();
module.exports = (packagesPath, packageName) => setupPackage(resolve(packagesPath), packageName);
12 changes: 12 additions & 0 deletions lib/get-log-gatherer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";

module.exports = () => {
const lines = [];
return {
lines,
logger: {
info(line) { lines.push(line); },
error(line) { throw new Error(`Unexpected error line ${ line }`); }
}
};
};
8 changes: 8 additions & 0 deletions lib/is-directory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"use strict";

const resolveStats = require("./resolve-stats");

module.exports = async path => {
const stats = await resolveStats(path);
return stats ? stats.isDirectory() : null;
};
24 changes: 24 additions & 0 deletions lib/is-own-package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use strict";

const logger = require("log4").get("setup-own-package")
, memoize = require("memoizee")
, GithubApi = require("@octokit/rest");

const github = new GithubApi({ timeout: 5000 });

github.authenticate({ type: "token", token: "[HIDDEN]" });

const getReposPage = async ({ page }) => {
// eslint-disable-next-line camelcase
const { data } = await github.repos.getForUser({ username: "medikoo", page, per_page: 100 });
const repos = data.filter(repo => !repo.fork).map(repo => repo.name);
if (data.length === 100) repos.push(...(await getReposPage({ page: page + 1 })));
return repos;
};

const getRepos = memoize(async () => {
logger.notice("resolve own package names");
return new Set(await getReposPage({ page: 1 }), { promise: true });
});

module.exports = async packageName => (await getRepos()).has(packageName);
22 changes: 22 additions & 0 deletions lib/is-package-linked.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict";

const logger = require("log4").get("setup-own-package")
, { resolve } = require("path")
, memoize = require("memoizee")
, getLogGatherer = require("./get-log-gatherer")
, isSymbolicLink = require("./is-symbolic-link")
, runProgram = require("./run-program");

const getNpmPathPrefix = memoize(async () => {
const { lines, logger: gatherer } = getLogGatherer();
await runProgram("npm", ["config", "get", "prefix"], { cwd: process.cwd(), logger: gatherer });
const [npmPathPrefix] = lines;
if (!npmPathPrefix) throw new Error("Could not resolve npm path prefix");
logger.notice("resolved npm path prefix %s", npmPathPrefix);
return npmPathPrefix;
});

module.exports = async packageName => {
const npmPathPrefix = await getNpmPathPrefix();
return isSymbolicLink(resolve(npmPathPrefix, "lib/node_modules", packageName));
};
8 changes: 8 additions & 0 deletions lib/is-symbolic-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"use strict";

const resolveStats = require("./resolve-stats");

module.exports = async path => {
const stats = await resolveStats(path);
return stats ? stats.isSymbolicLink() : null;
};
12 changes: 12 additions & 0 deletions lib/resolve-stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";

const lstat = require("fs2/lstat");

module.exports = async path => {
try {
return await lstat(path);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
}
};
19 changes: 19 additions & 0 deletions lib/rm-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use strict";

const rmdir = require("fs2/rmdir")
, unlink = require("fs2/unlink")
, logger = require("log4").get("setup-own-package")
, isDirectory = require("./is-directory");

module.exports = async path => {
const isDir = await isDirectory(path);
if (isDir) {
logger.notice("remove directory %s", path);
return rmdir(path, { recursive: true, force: true });
}
if (isDir === false) {
logger.notice("remove file %s", path);
return unlink(path);
}
return null;
};
43 changes: 43 additions & 0 deletions lib/run-program.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use strict";

const { spawn } = require("child_process")
, Deferred = require("deferred");

const newLineRe = /[\n\r]/u;

const processOutput = (stream, logger) => {
let buffer = "";
const flush = isFinal => {
if (!buffer) return;
if (!buffer.match(newLineRe)) {
if (!isFinal) return;
logger(buffer);
return;
}
const lines = buffer.split(newLineRe);
buffer = isFinal ? "" : lines.pop();
for (const line of lines) logger(line);
};

stream.on("data", data => {
buffer += data;
flush();
});
stream.on("error", flush);
stream.on("end", flush);
};

module.exports = (command, args, options) => {
const { logger } = options
, deferred = new Deferred()
, child = spawn(command, args, { cwd: options.cwd });

child.on("error", deferred.reject);
processOutput(child.stdout, logger.info);
processOutput(child.stderr, logger.notice);
child.on("close", code => {
if (code) deferred.reject(new Error(`Program exited with: ${ code }`));
else deferred.resolve();
});
return deferred.promise;
};
18 changes: 18 additions & 0 deletions lib/setup-npm-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";

const { basename, resolve } = require("path")
, logger = require("log4").get("setup-own-package")
, isSymbolicLink = require("./is-symbolic-link")
, rmPath = require("./rm-path")
, runProgram = require("./run-program");

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 rmPath(dependencyLinkPath);
await runProgram("npm", ["link", dependencyName], {
cwd: packagePath,
logger: logger.levelRoot.get("npm:link")
});
};
Loading

0 comments on commit 8471227

Please sign in to comment.