pax_global_header00006660000000000000000000000064127544115100014512gustar00rootroot0000000000000052 comment=1a1d85b52c6b08c7aa8cabc84c4f0a6a054f68d7 cpr-2.0.0/000077500000000000000000000000001275441151000122755ustar00rootroot00000000000000cpr-2.0.0/.gitignore000066400000000000000000000002241275441151000142630ustar00rootroot00000000000000**/node_modules/ **/npm-debug.log node_modules/ coverage/ artifacts/ tmp/ CVS/ .DS_Store .*.swp .svn *~ .com.apple.timemachine.supported tests/out/ cpr-2.0.0/.istanbul.yml000066400000000000000000000002661275441151000147230ustar00rootroot00000000000000reporting: reports: - lcov - text - text-summary check: global: statements: 100 lines: 100 branches: 95 functions: 97 cpr-2.0.0/.travis.yml000066400000000000000000000000471275441151000144070ustar00rootroot00000000000000language: node_js node_js: - '4' - '6' cpr-2.0.0/LICENSE000066400000000000000000000027141275441151000133060ustar00rootroot00000000000000Copyright 2012 Yahoo! Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Yahoo! Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cpr-2.0.0/README.md000066400000000000000000000036361275441151000135640ustar00rootroot00000000000000CPR (cp -R) =========== There are other modules out there that attempt this, but none did it the way I needed it to be done or they had issues and the author failed to fix them in a timely manner. Install ------- npm install cpr Build Status ------------ [![Build Status](https://secure.travis-ci.org/davglass/cpr.png)](http://travis-ci.org/davglass/cpr) Usage ----- ```js var cpr = require('cpr'); //or var cpr = require('cpr').cpr; //Back compat cpr('/path/from', '/path/to', { deleteFirst: true, //Delete "to" before overwrite: true, //If the file exists, overwrite it confirm: true //After the copy, stat all the copied files to make sure they are there }, function(err, files) { //err - The error if any (err.list might be available with an array of errors for more detailed information) //files - List of files that we copied }); cpr('/path/from', '/path/to', function(err, files) { //err - The error if any (err.list might be available with an array of errors for more detailed information) // In the case of an error, cpr continues to copy files but returns this error object with all of the files that it failed to copy. //files - List of files that we copied }); ``` Options ------- All options default to `false`. * `deleteFirst`: Delete the to directory with `rimraf` * `overwrite`: If the destination exists, overwrite it * `confirm`: After the copy operation, stat all the files and report errors if any are missing * `filter`: `RegExp` or `function` to test each file against before copying Filtering --------- If you give it a `RegExp`, it will use that to `test` the filename as they are being gathered. If it passes, it will be removed. If you give it a `function`, it will use that with `Array.filter` on the list of files. CLI --- `cpr` can also be used from the command line which is useful for cross platform support. ![cpr](../master/cpr.jpg?raw=true) cpr-2.0.0/bin/000077500000000000000000000000001275441151000130455ustar00rootroot00000000000000cpr-2.0.0/bin/cpr000077500000000000000000000011371275441151000135610ustar00rootroot00000000000000#!/usr/bin/env node var cpr = require('../lib'); var fs = require('fs'); var minimist = require('minimist'); var argv = minimist(process.argv.slice(2), { alias: { d:'delete-first', h:'help', o:'overwrite', v:'version' } }); if (argv.v) { console.log(require('../package.json').version); return; } if (argv.h) { fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout); return; } cpr(argv._[0], argv._[1], { deleteFirst: argv.d, overwrite: argv.o }, function (err) { if (err) { console.error('Error: ' + err.message); process.exit(1); } }); cpr-2.0.0/bin/usage.txt000077500000000000000000000005271275441151000147210ustar00rootroot00000000000000Usage: cpr [options] Copies files from one directory to another. Options: -d, --delete-first Delete the destination directory before copying. -h, --help Display this usage info. -o, --overwrite Overwrite the destination exists if it exists. -v, --version Display the cpr version. cpr-2.0.0/cpr.jpg000066400000000000000000000352001275441151000135630ustar00rootroot00000000000000JFIFHHC    #%$""!&+7/&)4)!"0A149;>>>%.DIC; X"R  !1AQaq"2BV#SUCRTbt$36r57s%D4c?.!aTo4֧#{Ne+ A%sbO28Q=%Oqb\q5r3mkRF.nN9VJus=}i'sO5ߦO̖yܸRcu5+ ;RȞ Ozle+r瑔5\&]z7.g }i )5DenqS5dOr{fV8r5];TÀH>,N O52ԼDb4 U5 f2F.htҴCga~ [&+Rx3F&{8׬Օ8\us>yrIx6ߕVn*#.;rv9>)++C[MCYI3fv#㑻O@{ZRڰӱ\ܼMNu\7Yqc58s'Sa-{>-Ui\HսIӵ+-_P'D]\Ѩ "pO-5Ds",OG"-uqdDkZ9=Fl.HTۿv9vbxYT;"D0ML?dmDHMW|Z^c Ib5-8ie2\cw @>j ,)R5SOKr [H-]@o_z-Mm_6[k"8kF*>JxOVx4E]f paX,*,y]nOq!ؒa+_i^_TɿB.y mǢḤƋ׍~ի KpS*b*S`M'9crr;@®DW~ &Ipw76Ttq/5=eOrs!VⵏEHr\ǘ @x[&'E~LMUߗN4m9' gJjrj/JfHCjڸiiY&lMrH(nQ-Or'USBӮ:. +5lr8n;%]^jd;Wg"Id)jaV G.hT;p_K:JWkkQچ.Y^R0[XE@45=vnszU GYK]v{jBc&hM҅Z0*s뙫,<=NNeM4[Нպ+b3e;~?6s]UL4THءۚLJ{\]=V&ͅWӱ}HNՠ˪IHZ+ssTTRbif}mC8bznW\5&m IW%LֆGqy:Ӑt`R޸j91*vλ7;W῕XmfMA_N*avzmESwUxVEJ> *|ɱd_g?*t: FGw5OLAn%"ۘEB:7kWmEڼDǣAedlNrMW@)Xt?k4ZXS=UE^ff}E,Lɢ{$nG5\QQK!] v᭣ũ?(8Lbᷥ2+"j=SS5g2ovEvbԭlRk|~ 9 l-2GIGs`_6Ykyjr==.Dx#d5cQ>CK*bcvmb嬜mbrCʹ݁H|z'j鰷ruXLuU;j뛥{=@i!'#$nVʊUQVU5S͎_YN#- ͍4jj[A_7=mC@hm~ *G_b'Ky(pC%MDpBI$F1LU:OcZV6/ RTrs!B`~pS_!hus_DܭEޗ.Ό <5FDb!J;ˉk"\fI97ܩҼӣ֕ \_j|_K%q͂ZdNELkکEE*jhdwRSҍwu5RН0%zէ6>eMPߴvy7jde~!QdX]*V,cz1W9˒"&jYZ,x9MTG*loM9=nTsd=5'"z.TUutUqSF/rS B+s*sPiN|b9OmzzO!Z2\zp:ĩ8J8ʫi-kv Ȑ˽^J/n5JHv/Jkk@I:<=MSoNDr}tQGzV'S'ncV;KR/@ՙ쑾WPV%Mt؍cI#wKΛK4PbNY$޿I:WeusŻ8h=EؘEEJI2~K߼:5 jqRdD_7im \S*=} >%A=\i, XbS%*mZN>nlk FE0K<Kz2dʲѪޜ輤wt]ULHhdTD~ ̪Uj9誣XEF/rT:ۘMɏRa4+r&jZh0kd,VAcSjvn:VeTlՉ8c[`&Y ۛf-5"iR$kխUTL A:?߸U?Vɨ_69d]ԼDOMrAPˢ,2u^˔,;KF炿5ZgK֍WoZlT-rEWL#s%V׵Sb󢢕IVWDB̨jxvΌDgiuERe5W"no])m~O4blv:W$*%_QbUoמGI#UW3>Z+5U:MbZV>ըrxJzR.ܜikNYoRK55]r}"1ѮLULz,7PF,>/O)䤫[Dd/:s)bmFYIORŎF"s9U.~ظ*л_EҟwНrOMצW/_r!iK֚&"*=&w!X7$\r۟!fki%kEѣkx˹e6tFm~PţeΞu5Wc]ȿE`Ƅ_rVG4VR&[]_zF+R]F#XJzhG2q'?T,rǪZʉ5Ln92Bh[q"&Ls4w쵞rʪe+ԸZlVX$k78v!MWʒ1$Ɗh:cSZ j$;ܝ):CjjvSSHDc̩uhLvqNU|;Ίis 4wp5jI""eȫUrEj[X]+R/")2)Uj*%w{޻\}X`85URTmjljqy3^E.atLՂ*:j$G $+^_5KX]1z=%i&[q:`UQw% ~-Rb_Unr/׽9&"9JV'j\Zx0TMu* 0 Ewڸ߉V˫9UrKXTsQɒN2ir.Uuv>oYz#'} Y'n"ʦȹ~9Mi{v| >m2bUUȲOQ#\MуpdsUaUyT`V~'OpO--DuH=E:E`ݱ]5qSՑ~\=GjGw[3dԪgR}Y6&|zy<2SO$1c7+okrT^mz8upS&UݨirN HwKmNj\K4uMr53_qW=9\\UsU8%k>))ON(vJD-$1G,&##ֵv/&M"&d7Νb4 <`1MNZx*cV=8ӑS%NXUa5HkS%1tMiuGQ;hplfgЊKZVڵ_<ڕ,PjַR.]*lqkPaʒ;=I78ס9K ѥ+nFSʮ|9}g{ ,Z0Ol'~? {0|Vũ*<E4/:/2hZk*lVrdUcrlsWtg&;Gux{>u6T|68ڮ{DUW6iSֲDo_Tڙ56u&ݗUE[$9JZ.\׭ \vR]W %4k$=#UZ6نԶptMyOH ̈k[]EM&~"<%^b cf"%""|!]?HREjd)/_+΄l}Y*UXQScwR.]+M5<MW֢fEX.n۞Ur@R$ֻUyJ{W U#Ǔʀa Of2QfEBEȲ)緒Tv#@^t2ZBYw2FH秪^#kvU$&DL_orá75sUb*7R/z):+{l*;TW/2&E6RtmT4csU^u\׬tw%vOɯPvD>yH vw /C"*HJVirFtBḅ.+A_G*KOP|oN4_״#2.Jwq+ڋRqOtݩ:nNfu[8<~#{'k7g7$]ʋm7vrJw$h[D*k=Z\Jpvsm,YIU'ǞO]hᤦQ152F$D"4VcuSN]Q5TS=r-ר<=;KS<=;KSt#zL*ju;S#GH֮X0C#LcQ2fmW=kZrϏ`ԪQ¨ʏcW.]x}[;|}[;<}[;|}[;CnlGծLR~' NVʏ\ktdzU6%U&;oBT?Ωnő=ZƜ{jij(OS j^tS#dl陞%BSZdVF}.̰eAf GIHꊇ&N߂'qt9Fi3NQ/=1g!f3NPr.{Xsj&j"3OmF/ҷT:<֦݉i&$rj sVMW^~zZ4_E?_{iUWXsrN3 -L9],Hޯrgr>)$nV=k**nTRtޗ ģ lت޹2ng.滟r.QDTTTS]aeay"xxZzP^+asYLTϟ#&;޵w5)T|SwJGix +I:UwmaK׼]"724&^ozn U\j{>xJp*ޝCۺGqHuj&5r?^\s?yE%:$qI^{{;W|S؏?;|S؏?;ȹEE]wr#ُbHh7'yHw Tm^.ߙK/\a$L)ӝI<4)5t*^_EɿPv6NwS~N3gthdډjh>~ en%KVf NކC3p3Ac1i|g9ssڽHEs@n娬LzWqdsLR-mXӡ| 82<;t/T4Nf4Ngf1a*zΧvkvGUN/ T˖YMʦ_f&zU rdܓ#_sʪ8Q$26H=\QzMo=VJV?%Po_SsBro,Z6b'dgʜπ\GnY\ʫGm!kY۳8WV$_SBtrԹEMEDܨők:I%Ve|?v&GE) s53`vRdIG\޲êjn0j6f\:Eח$BeU TU0?ђ'hz@jL6Jژ3|"N2b!VⵏEHr\ǘ8q:TBEN4^4,vRx HEԞl']輆f3irpkYwVdDTbҪ}R]7=v䮫s)ue$Ky3OYy3[e+ϼ@5lO S"|,js7~%wo\b؄ڰWG8yokHdï/UAFVvH:nidGW5XٚOݥ kz5wiy Ϗӹ]7ƪ*w,hN'xw,hN'y v@;~C/L((=nlW&ժq#?(Y5L櫑ЮIt3^ dhѵLNSH;ov raؓW/c2} Q$z3;K74yi{9f /g0ٚ<{3Nk6٢hF@sU7*)ߍ[=șPEVUV4?5W~1<ٞx~t{h@k-E\\ /g0ٚwCg[4VoE\7]TܪT<@aZ{ ]#L~m 7 J7-PILkj#G.+n|Ch2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝ㆻh2w8k~'xZ>̝m6.e֙ kVQP,0a\xv#NulE*"^elWXCk"bgOR;jW"PJD2~h$&ƢqIUTm&&ZMKPr'_sc0>tTקlVvmN a1TG#۵U$%ƯY\XpZ.6)ʞ&M*-ty.~}CNW"3+ `/V'27/uW्-^ r"Jen֯ʥUZj=X92V%E:,?&VOPZCViMn^c:sU5M>⊑8KWc&|k~ߢLrɹDʙ#4Nd*fCcNjoDO7HXV4v낭)Xd&;p]~jqRdW;z1\1Q3ؙ;q ) yv#9y:2JbG+vb/Ykʦ|\񐞑E%3-$.Ut,MƜiӋfQQrT@HZ>euQ!C%.v5FREK-,,6&Mj&D;eC&/@c5"=sS<*/*}nܮ)Uw"H׵=WhdU\?c*|Zvo DUJ̾WȆG}*oW*7<8"l.f%6)Ւal{w=>8?軸|S8?軸|S8?軸fb>,ͥz%.'p^w%.'p^w%.'p^w%.'p^w%.'p^wqZ7$ԏĜw v7W!.f>%'_<}+oxepoB]}KټOy v7W!.f>-'_zSFד-֢ͩ~#[s{~ o/g^857pky{?Wox~_[s{~h=Lt~ϽoOP/_?Q?ECk'pM|D "5D_8&~h;z9pȘ꺦<}5z_jp5z_jh>eu6iRN734:YZ9#EMdr.JdI6Z1}KUS.NL"s"!K4]]JbW5zw;b?kY$e-'sOrdIsZSj䉵xqj |0;qSl˕3ڽHhhoef**۵s2ʍ_IyH興r e2tF]#.d2 C!d2 C!d2 C$' 9I2NAr d$' 9H2 C!d29˷ q 6g/k6:hZOz-R?j8!ԕ&Wjn UKMRKO=ep<"f¨]ɯ;z!o)cpr-2.0.0/lib/000077500000000000000000000000001275441151000130435ustar00rootroot00000000000000cpr-2.0.0/lib/index.js000066400000000000000000000237701275441151000145210ustar00rootroot00000000000000/* Copyright (c) 2012, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://yuilibrary.com/license/ */ var fs = require('graceful-fs'); var Stack = require('./stack').Stack; var path = require('path'); var rimraf = require('rimraf'); var mkdirp = require('mkdirp'); var getTree = function(from, options, callback) { var stack = new Stack(), errors = [], results = {}; options.stats = options.stats || {}; options.toHash = options.toHash || {}; fs.readdir(from, stack.add(function(err, dirs) { if (!dirs.length) { results[from] = true; fs.stat(from, stack.add(function(err, stat) { /*istanbul ignore next*/ if (err) { return errors.push(err); } options.stats[from] = stat; options.toHash[from] = path.join(options.to, path.relative(options.from, from)); })); } dirs.forEach(function (dir) { var base = path.join(from, dir); fs.stat(base, stack.add(function(err, stat) { options.stats[base] = stat; options.toHash[base] = path.join(options.to, path.relative(options.from, base)); /*istanbul ignore next*/ if (err) { return errors.push(err); } if (stat.isDirectory()) { getTree(base, options, stack.add(function(errs, tree) { /*istanbul ignore next*/ if (errs && errs.length) { errs.forEach(function(item) { errors.push(item); }); } //tree is always an Array tree.forEach(function(item) { results[item] = true; }); })); } else { results[base] = true; } })); }); })); stack.done(function() { callback(errors, Object.keys(results).sort()); }); }; var filterTree = function (tree, options, callback) { var t = tree; if (options.filter) { if (typeof options.filter === 'function') { t = tree.filter(options.filter); } else if (options.filter instanceof RegExp) { t = tree.filter(function(item) { return !options.filter.test(item); }); } } callback(null, t); }; var splitTree = function (tree, options, callback) { var files = {}, dirs = {}; tree.forEach(function(item) { var to = options.toHash[item]; if (options.stats[item] && options.stats[item].isDirectory()) { dirs[item] = true; } else { dirs[path.dirname(item)] = true; options.stats[path.dirname(item)] = fs.statSync(path.dirname(item)); options.toHash[path.dirname(item)] = path.dirname(to); } }); tree.forEach(function(item) { if (!dirs[item]) { files[item] = true; } }); callback(Object.keys(dirs).sort(), Object.keys(files).sort()); }; var createDirs = function(dirs, to, options, callback) { var stack = new Stack(); dirs.forEach(function(dir) { var stat = options.stats[dir], to = options.toHash[dir]; /*istanbul ignore else*/ if (to && typeof to === 'string') { fs.stat(to, stack.add(function(err, s) { if (s && !s.isDirectory()) { options.errors.push(new Error(to + ' exists and is not a directory, can not create')); } else { mkdirp(to, stat.mode, stack.add(function(err) { /*istanbul ignore next*/ if (err) { options.errors.push(err); } })); } })); } }); stack.done(function() { callback(); }); }; var copyFile = function(from, to, options, callback) { var dir = path.dirname(to); mkdirp(dir, function() { fs.stat(to, function(statError) { if(!statError && options.overwrite !== true) { return callback(new Error('File '+to+' exists')); } var fromFile = fs.createReadStream(from), toFile = fs.createWriteStream(to), err, called = false, cb = function(e) { if (!called) { callback(e); called = true; } }, onError = function (e) { /*istanbul ignore next*/ err = e; cb(e); }; fromFile.on('error', onError); toFile.on('error', onError); fromFile.once('end', function() { cb(err); }); fromFile.pipe(toFile); }); }); }; var createFiles = function(files, to, options, callback) { var next = process.nextTick, complete = 0, count = files.length, check = function() { /*istanbul ignore else - Shouldn't need this if graceful-fs does it's job*/ if (count === complete) { callback(); } }, copy = function() { var from = files.pop(), to = options.toHash[from], bail; if (!from) { return check(); } copyFile(from, to, options, function(err) { /*istanbul ignore next*/ //This shouldn't happen with graceful-fs, but just in case if (/EMFILE/.test(err)) { bail = true; files.push(from); } else if (err) { options.errors.push(err); } /*istanbul ignore next*/ if (!bail) { complete++; } next(copy); }); }; copy(); }; var confirm = function(files, options, callback) { var stack = new Stack(), errors = [], f = [], filtered = files; if (options.filter) { if (typeof options.filter === 'function') { filtered = files.filter(options.filter); } else if (options.filter instanceof RegExp) { filtered = files.filter(function(item) { return !options.filter.test(item); }); } } /*istanbul ignore else - filtered should be an array, but just in case*/ if (filtered.length) { filtered.forEach(function(file) { fs.stat(file, stack.add(function(err, stat) { /*istanbul ignore next*/ if (err) { errors.push(err); } else { if (stat && (stat.isFile() || stat.isDirectory())) { f.push(file); } } })); }); } stack.done(function() { /*istanbul ignore next */ callback(((errors.length) ? errors : null), f.sort()); }); }; var cpr = function(from, to, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } var options = {}, proc; Object.keys(opts).forEach(function(key) { options[key] = opts[key]; }); options.from = from; options.to = to; options.errors = []; proc = function() { getTree(options.from, options, function(err, tree) { filterTree(tree, options, function(err, t) { splitTree(t, options, function(dirs, files) { if (!dirs.length && !files.length) { return callback(new Error('No files to copy')); } createDirs(dirs, to, options, function() { createFiles(files, to, options, function() { var out = [], err; Object.keys(options.toHash).forEach(function(k) { out.push(options.toHash[k]); }); if (options.confirm) { confirm(out, options, callback); } else if (!options.errors.length) { callback(null, out.sort()); } else { /*istanbul ignore next*/ err = new Error('Unable to copy directory' + (out.length ? ' entirely' : '')); /*istanbul ignore next*/ err.list = options.errors; /*istanbul ignore next*/ callback(err, out.sort()); } }); }); }); }); }); }; fs.stat(options.from, function(err, stat) { if (err) { return callback(new Error('From should be a file or directory')); } if (stat && stat.isDirectory()) { if (options.deleteFirst) { rimraf(to, function() { proc(); }); } else { proc(); } } else { if (stat.isFile()) { var dirRegex = new RegExp(path.sep + '$'); if (dirRegex.test(to)) { // Create directory if has trailing separator to = path.join(to, path.basename(options.from)); } return copyFile(options.from, to, options, callback); } callback(new Error('From should be a file or directory')); } }); }; //Preserve backward compatibility cpr.cpr = cpr; //Export a function module.exports = cpr; cpr-2.0.0/lib/stack.js000066400000000000000000000017311275441151000145100ustar00rootroot00000000000000/* Copyright (c) 2012, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://yuilibrary.com/license/ */ var Stack = function () { this.errors = []; this.finished = 0; this.results = []; this.total = 0; }; Stack.prototype = { add: function (fn) { var self = this, index = self.total; self.total += 1; return function (err) { if (err) { self.errors[index] = err; } self.finished += 1; self.results[index] = fn.apply(null, arguments); self.test(); }; }, test: function () { if (this.finished >= this.total && this.callback) { this.callback.call(null, this.errors.length ? this.errors : null, this.results, this.data); } }, done: function (callback, data) { this.callback = callback; this.data = data; this.test(); } }; exports.Stack = Stack; cpr-2.0.0/package.json000066400000000000000000000024551275441151000145710ustar00rootroot00000000000000{ "name": "cpr", "description": "cp -R", "author": "Dav Glass ", "version": "2.0.0", "dependencies": { "graceful-fs": "^4.1.5", "minimist": "^1.2.0", "mkdirp": "~0.5.1", "rimraf": "^2.5.4" }, "main": "./lib/index.js", "bin": "./bin/cpr", "devDependencies": { "istanbul": "~0.4.4", "jenkins-mocha": "^3.0.0", "jshint": "^2.9.2", "yui-lint": "~0.2.0" }, "contributors": [ "soyuka ", "fresheneesz ", "silverwind ", "Peter deHaan ", "André Cruz ", "Brian J Brennan ", "Elijah Insua ", "Jonny Reeves ", "Lydie Danet " ], "keywords": [ "copy", "recursive", "cp -r", "cp" ], "scripts": { "pretest": "jshint --config ./node_modules/yui-lint/jshint.json ./lib/", "windows-test": "jenkins-mocha ./tests/full.js", "test": "jenkins-mocha ./tests/full.js", "posttest": "istanbul check-coverage" }, "bugs": { "url": "http://github.com/davglass/cpr/issues" }, "license": "BSD-3-Clause", "repository": { "type": "git", "url": "http://github.com/davglass/cpr.git" } } cpr-2.0.0/tests/000077500000000000000000000000001275441151000134375ustar00rootroot00000000000000cpr-2.0.0/tests/full.js000066400000000000000000000337051275441151000147470ustar00rootroot00000000000000var assert = require('assert'), path = require('path'), fs = require('fs'), rimraf = require('rimraf'), mkdirp = require('mkdirp'), cpr = require('../lib'), exec = require('child_process').exec, to = path.join(__dirname, './out/'), from = path.join(__dirname, '../node_modules'); describe('cpr test suite', function() { this.timeout(55000); describe('loading', function() { before(function() { rimraf.sync(to); }); it('should export raw method', function () { assert.equal(typeof cpr, 'function'); }); it('should export cpr method too', function () { assert.equal(typeof cpr.cpr, 'function'); }); }); describe('should copy node_modules', function() { var out = path.join(to, '0'); var data = {}; before(function(done) { cpr(from, out, function(err, status) { data = { from: fs.readdirSync(from).sort(), to: fs.readdirSync(out).sort() }; done(); }); }); it('has ./out/0', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are equal', function() { assert.deepEqual(data.to, data.from); }); it('from directory has graceful-fs dir', function() { var fromHasGFS = data.from.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, fromHasGFS); }); it('to directory has graceful-fs dir', function() { var toHasGFS = data.to.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, toHasGFS); }); }); describe('should NOT copy node_modules', function() { var out = path.join(to, '1'), data; before(function(done) { cpr(from, out, { filter: /node_modules/ }, function(err) { fs.stat(out, function(e, stat) { data = { err: err, stat: e }; done(); }); }); }); it('does not have ./out/1', function() { assert.ok(data.stat); // Should be an error }); it('threw an error', function() { assert(data.err instanceof Error); // Should be an error assert.equal(data.err.message, 'No files to copy'); }); }); describe('should not copy yui-lint from regex', function() { var out = path.join(to, '2'), data; before(function(done) { cpr(from, out, { confirm: true, overwrite: true, filter: /yui-lint/ }, function(err, status) { data = { status: status, dirs: { from: fs.readdirSync(from).sort(), to: fs.readdirSync(out).sort() } }; done(); }); }); it('returns files array with confirm', function() { assert.ok(Array.isArray(data.status)); assert.ok(data.status.length > 0); }); it('has ./out/2', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are not equal', function() { assert.notDeepEqual(data.dirs.to, data.dirs.from); }); it('from directory has yui-lint dir', function() { var fromHasLint = data.dirs.from.some(function(item) { return (item === 'yui-lint'); }); assert.equal(true, fromHasLint); }); it('to directory does not have yui-lint dir', function() { var toHasLint = data.dirs.to.some(function(item) { return (item === 'yui-lint'); }); assert.equal(false, toHasLint); }); }); describe('should not copy directory from function', function() { var out = path.join(to, '3'), data; before(function(done) { cpr(from, out, { confirm: true, deleteFirst: true, filter: function (item) { return !(/data/.test(item)); } }, function(err, status) { data = { status: status, dirs: { from: fs.readdirSync(path.join(from, 'jshint/')).sort(), to: fs.readdirSync(path.join(out, 'jshint/')).sort() } }; done(); }); }); it('has ./out/3', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are not equal', function() { assert.notDeepEqual(data.dirs.to, data.dirs.from); }); it('from directory has data dir', function() { var fromHas = data.dirs.from.some(function(item) { return (item === 'data'); }); assert.equal(true, fromHas); }); it('to directory does not have data dir', function() { var toHas = data.dirs.to.some(function(item) { return (item === 'data'); }); assert.equal(false, toHas); }); }); describe('should copy minimatch from bad filter', function() { var out = path.join(to, '4'), data; before(function(done) { cpr(from, out, { confirm: true, deleteFirst: true, filter: 'bs content' }, function(err, status) { data = { status: status, dirs: { from: fs.readdirSync(path.join(from, 'jshint/node_modules')).sort(), to: fs.readdirSync(path.join(out, 'jshint/node_modules')).sort() } }; done(); }); }); it('has ./out/4', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are not equal', function() { assert.deepEqual(data.dirs.to, data.dirs.from); }); it('from directory has minimatch dir', function() { var fromHasGFS = data.dirs.from.some(function(item) { return (item === 'minimatch'); }); assert.equal(true, fromHasGFS); }); it('to directory does have minimatch dir', function() { var toHasGFS = data.dirs.to.some(function(item) { return (item === 'minimatch'); }); assert.equal(true, toHasGFS); }); }); describe('should copy node_modules with overwrite flag', function() { var out = path.join(to, '4'), data; before(function(done) { cpr(from, out, function() { cpr(from, out, { overwrite: true, confirm: true }, function(err, status) { data = { status: status, dirs: { from: fs.readdirSync(from).sort(), to: fs.readdirSync(out).sort() } }; done(); }); }); }); it('should return files array', function() { assert.ok(Array.isArray(data.status)); assert.ok(data.status.length > 0); }); it('has ./out/0', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are equal', function() { assert.deepEqual(data.dirs.to, data.dirs.from); }); it('from directory has graceful-fs dir', function() { var fromHasGFS = data.dirs.from.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, fromHasGFS); }); it('to directory has graceful-fs dir', function() { var toHasGFS = data.dirs.to.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, toHasGFS); }); }); describe('error handling', function() { it('should fail on non-existant from dir', function(done) { cpr('./does/not/exist', path.join(to, 'does/not/matter'), function(err, status) { assert.equal(undefined, status); assert(err instanceof Error); assert.equal('From should be a file or directory', err.message); done(); }); }); it('should fail on non-file', function(done) { cpr('/dev/null', path.join(to, 'does/not/matter'), function(err, status) { assert.equal(undefined, status); assert(err instanceof Error); assert.equal('From should be a file or directory', err.message); done(); }); }); it('should return an error if a directory is to write over an existing file with the same name', function(done) { mkdirp.sync(path.join(to, 'empty-src2', 'a')); mkdirp.sync(path.join(to, 'empty-dest2')); fs.writeFileSync(path.join(to, 'empty-dest2', 'a'), 'FILE'); cpr(path.join(to, 'empty-src2'), path.join(to, 'empty-dest2'), { overwrite: true }, function(errs) { var stat = fs.statSync(path.join(to, 'empty-dest2')); assert.ok(stat.isDirectory()); assert.ok(errs); assert.ok(errs.list); assert.ok(errs.list[0]); assert.ok(errs.list[0].message.match(/exists and is not a directory, can not create/)); done(); }); }); it('should fail without write permissions', function(done) { var baddir = path.join(to, 'readonly'); mkdirp.sync(baddir); fs.chmodSync(baddir, '555'); cpr(from, baddir, function(errs, status) { assert.ok(errs); assert.ok(errs.list); assert.ok(errs.list[0]); assert.ok(errs.message.match(/Unable to copy directory entirely/)); done(); }); }); }); describe('validations', function() { it('should copy empty directory', function(done) { mkdirp.sync(path.join(to, 'empty-src')); cpr(path.join(to, 'empty-src'), path.join(to, 'empty-dest'), function() { var stat = fs.statSync(path.join(to, 'empty-dest')); assert.ok(stat.isDirectory()); done(); }); }); it('should not delete existing folders in out dir', function(done) { mkdirp.sync(path.join(to, 'empty-src', 'a')); mkdirp.sync(path.join(to, 'empty-dest', 'b')); cpr(path.join(to, 'empty-src'), path.join(to, 'empty-dest'), { overwrite: true }, function() { var stat = fs.statSync(path.join(to, 'empty-dest')); assert.ok(stat.isDirectory()); var dirs = fs.readdirSync(path.join(to, 'empty-dest')); assert.equal(dirs[0], 'a'); assert.equal(dirs[1], 'b'); done(); }); }); it('should copy one file', function(done) { cpr(__filename, path.join(to, 'one-file-test.js'), { overwrite: true }, function(err) { assert.equal(undefined, err); var stat = fs.statSync(path.join(to, 'one-file-test.js')); assert.ok(stat.isFile()); done(); }); }); it('should copy one file in dir if to has trailing sep', function(done) { cpr(__filename, path.join(to, 'one-file-dir'+path.sep), { overwrite: true }, function(err) { assert.equal(undefined, err); var stat = fs.statSync(path.join(to, 'one-file-dir','full.js')); assert.ok(stat.isFile()); done(); }); }); it('should not copy because file exists', function(done) { cpr(__filename, path.join(to, 'one-file-test.js'), function(err, status) { assert.equal(undefined, status); assert(err instanceof Error); assert.ok(/^File .* exists$/.test(err.message)); done(); }); }); }); describe('should work as a standalone bin', function() { var out = path.join(to, '4'), data; before(function(done) { exec('node ./bin/cpr ' + from + ' ' + out, function(err) { data = { dirs: { from: fs.readdirSync(from).sort(), to: fs.readdirSync(out).sort() } }; done(); }); }); it('has ./out/4', function() { var stat = fs.statSync(out); assert.ok(stat.isDirectory()); }); it('dirs are equal', function() { assert.deepEqual(data.dirs.to, data.dirs.from); }); it('from directory has graceful-fs dir', function() { var fromHasGFS = data.dirs.from.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, fromHasGFS); }); it('to directory has graceful-fs dir', function() { var toHasGFS = data.dirs.to.some(function(item) { return (item === 'graceful-fs'); }); assert.equal(true, toHasGFS); }); }); });