| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- const path = require('path');
- const Git = require('./git.js');
- const async = require('async');
- const fs = require('fs-extra');
- /**
- * Generate a list of unique directory paths given a list of file paths.
- * @param {Array<string>} files List of file paths.
- * @return {Array<string>} List of directory paths.
- */
- function uniqueDirs(files) {
- const dirs = {};
- files.forEach((filepath) => {
- const parts = path.dirname(filepath).split(path.sep);
- let partial = parts[0] || '/';
- dirs[partial] = true;
- for (let i = 1, ii = parts.length; i < ii; ++i) {
- partial = path.join(partial, parts[i]);
- dirs[partial] = true;
- }
- });
- return Object.keys(dirs);
- }
- exports.uniqueDirs = uniqueDirs;
- /**
- * Sort function for paths. Sorter paths come first. Paths of equal length are
- * sorted alphanumerically in path segment order.
- * @param {string} a First path.
- * @param {string} b Second path.
- * @return {number} Comparison.
- */
- function byShortPath(a, b) {
- const aParts = a.split(path.sep);
- const bParts = b.split(path.sep);
- const aLength = aParts.length;
- const bLength = bParts.length;
- let cmp = 0;
- if (aLength < bLength) {
- cmp = -1;
- } else if (aLength > bLength) {
- cmp = 1;
- } else {
- let aPart, bPart;
- for (let i = 0; i < aLength; ++i) {
- aPart = aParts[i];
- bPart = bParts[i];
- if (aPart < bPart) {
- cmp = -1;
- break;
- } else if (aPart > bPart) {
- cmp = 1;
- break;
- }
- }
- }
- return cmp;
- }
- exports.byShortPath = byShortPath;
- /**
- * Generate a list of directories to create given a list of file paths.
- * @param {Array<string>} files List of file paths.
- * @return {Array<string>} List of directory paths ordered by path length.
- */
- function dirsToCreate(files) {
- return uniqueDirs(files).sort(byShortPath);
- }
- exports.dirsToCreate = dirsToCreate;
- /**
- * Copy a file.
- * @param {Object} obj Object with src and dest properties.
- * @param {function(Error)} callback Callback
- */
- function copyFile(obj, callback) {
- let called = false;
- function done(err) {
- if (!called) {
- called = true;
- callback(err);
- }
- }
- const read = fs.createReadStream(obj.src);
- read.on('error', (err) => {
- done(err);
- });
- const write = fs.createWriteStream(obj.dest);
- write.on('error', (err) => {
- done(err);
- });
- write.on('close', () => {
- done();
- });
- read.pipe(write);
- }
- exports.copyFile = copyFile;
- /**
- * Make directory, ignoring errors if directory already exists.
- * @param {string} path Directory path.
- * @param {function(Error)} callback Callback.
- */
- function makeDir(path, callback) {
- fs.mkdir(path, (err) => {
- if (err) {
- // check if directory exists
- fs.stat(path, (err2, stat) => {
- if (err2 || !stat.isDirectory()) {
- callback(err);
- } else {
- callback();
- }
- });
- } else {
- callback();
- }
- });
- }
- /**
- * Copy a list of files.
- * @param {Array<string>} files Files to copy.
- * @param {string} base Base directory.
- * @param {string} dest Destination directory.
- * @return {Promise} A promise.
- */
- exports.copy = function (files, base, dest) {
- return new Promise((resolve, reject) => {
- const pairs = [];
- const destFiles = [];
- files.forEach((file) => {
- const src = path.resolve(base, file);
- const relative = path.relative(base, src);
- const target = path.join(dest, relative);
- pairs.push({
- src: src,
- dest: target,
- });
- destFiles.push(target);
- });
- async.eachSeries(dirsToCreate(destFiles), makeDir, (err) => {
- if (err) {
- return reject(err);
- }
- async.each(pairs, copyFile, (err) => {
- if (err) {
- return reject(err);
- } else {
- return resolve();
- }
- });
- });
- });
- };
- exports.getUser = function (cwd) {
- return Promise.all([
- new Git(cwd).exec('config', 'user.name'),
- new Git(cwd).exec('config', 'user.email'),
- ])
- .then((results) => {
- return {name: results[0].output.trim(), email: results[1].output.trim()};
- })
- .catch((err) => {
- // git config exits with 1 if name or email is not set
- return null;
- });
- };
|