"use strict"; const EventEmitter = require('events').EventEmitter; const path = require('path'); const fs = require('fs'); const async = require('async'); const Copier = require('recursive-tree-copy').Copier; const gitToFsCopier = new Copier({ concurrency: 4, walkSourceTree: (tree) => { const emitter = new EventEmitter(); process.nextTick(() => { let entries; try { entries = tree.gitTree.entries(); } catch(err) { return emitter.emit('error', err); } async.parallel(entries.map((entry) => (callback) => { if (entry.isTree()) { entry.getTree((err, subTree) => { if (err) { return callback(err); } emitter.emit('tree', { gitTree: subTree, name: entry.name() }); callback(); }); } else if (entry.isFile()) { emitter.emit('leaf', entry); callback(); } else { callback(); } }), (err) => { if (err) { return emitter.emit('error', err); } return emitter.emit('done'); }); }); return emitter; }, createTargetTree: (tree, targetDir, callback) => { const targetSubdir = path.join(targetDir, tree.name); fs.mkdir(targetSubdir, (err) => { if (err && err.code !== 'EEXIST' /* workaround for broken trees */) { return callback(err); } callback(undefined, targetSubdir); }); }, finalizeTargetTree: (targetSubdir, callback) => callback(), copyLeaf: (entry, targetDir, callback) => { const targetPath = path.join(targetDir, entry.name()); entry.getBlob((err, blob) => { if (err) { return callback(err); } fs.writeFile(targetPath, blob.content(), callback); }); } }); exports.gitToFs = (commit, exportDir, callback) => commit.getTree((err, tree) => { if (err) { return callback(err); } gitToFsCopier.copy({ gitTree: tree, name: "." }, exportDir, callback); });