Skip to content
Permalink
e363b144de
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
169 lines (158 sloc) 4.09 KB
const path = require('path');
const Git = require('./git');
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.
*/
const uniqueDirs = (exports.uniqueDirs = function(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);
});
/**
* 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.
*/
const byShortPath = (exports.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;
});
/**
* 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.
*/
const dirsToCreate = (exports.dirsToCreate = function(files) {
return uniqueDirs(files).sort(byShortPath);
});
/**
* Copy a file.
* @param {Object} obj Object with src and dest properties.
* @param {function(Error)} callback Callback
*/
const copyFile = (exports.copyFile = function(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);
});
/**
* 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;
});
};