'use strict'; var path = require('path'); var fs = require('fs'); var glob = require('glob'); var mkdirp = require('mkdirp'); var untildify = require('untildify'); var through = require('through2').obj; var noms = require('noms').obj; function toStream(array) { var length = array.length; var i = 0; return noms(function (done) { if (i >= length) { this.push(null); } this.push(array[i++]); done(); }); } function depth(string) { return path.normalize(string).split(path.sep).length - 1; } function dealWith(inPath, up) { if (!up) { return inPath; } if (up === true) { return path.basename(inPath); } if (depth(inPath) < up) { throw new Error('cant go up that far'); } return path.join.apply(path, path.normalize(inPath).split(path.sep).slice(up)); } var copyFile = _copyFile; function _copyFile (src, dst, opts, callback) { fs.createReadStream(src) .pipe(fs.createWriteStream(dst, { mode: opts.mode })) .once('error', callback) .once('finish', function () { fs.chmod(dst, opts.mode, function (err) { callback(err); }) }) } if (fs.copyFile) { copyFile = function (src, dst, opts, callback) { fs.copyFile(src, dst, callback); } } function makeDebug(config) { if (config.verbose) { return function (thing) { console.log(thing); } } return function () {} } module.exports = copyFiles; function copyFiles(args, config, callback) { if (typeof config === 'function') { callback = config; config = { up:0 }; } if (typeof config !== 'object' && config) { config = { up: config }; } var debug = makeDebug(config); var copied = false; var opts = config.up || 0; var soft = config.soft; if (typeof callback !== 'function') { throw new Error('callback is not optional'); } var input = args.slice(); var outDir = input.pop(); var globOpts = {}; if (config.exclude) { globOpts.ignore = config.exclude; } if (config.all) { globOpts.dot = true; } if (config.follow) { globOpts.follow = true; } outDir = outDir.startsWith('~') ? untildify(outDir) : outDir; toStream(input.map(function(srcP) {return srcP.startsWith('~') ? untildify(srcP) : srcP;})) .pipe(through(function (pathName, _, next) { var self = this; glob(pathName, globOpts, function (err, paths) { if (err) { return next(err); } paths.forEach(function (unglobbedPath) { debug(`unglobed path: ${unglobbedPath}`); self.push(unglobbedPath); }); next(); }); })) .on('error', callback) .pipe(through(function (pathName, _, next) { fs.stat(pathName, function (err, pathStat) { if (err) { return next(err); } var outName = path.join(outDir, dealWith(pathName, opts)); function done(){ mkdirp(path.dirname(outName)).then(()=>{ next(null, { pathName: pathName, pathStat: pathStat }); }, next); } if (pathStat.isDirectory()) { debug(`skipping, is directory: ${pathName}`) return next(); } if (!pathStat.isFile()) { return next(new Error('how can it be neither file nor folder?')) } if (!soft) { return done(); } fs.stat(outName, function(err){ if(!err){ //file exists return next() } if (err.code === 'ENOENT') { //file does not exist return done(); } // other error return next(err) }) }); })) .on('error', callback) .pipe(through(function (obj, _, next) { if (!copied) { copied = true; } var pathName = obj.pathName; var pathStat = obj.pathStat; var outName = path.join(outDir, dealWith(pathName, opts)); debug(`copy from: ${pathName}`) debug(`copy to: ${outName}`) copyFile(pathName, outName, pathStat, next) })) .on('error', callback) .on('finish', function () { if (config.error && !copied) { return callback(new Error('nothing coppied')); } callback(); }); }