UNPKG

pauls-dat-api

Version:

Library of functions that make working with dat / hyperdrive easier.

392 lines (244 loc) 23.3 kB
'use strict';function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}var assert = require('assert'); var path = require('path'); var fse = require('fs-extra'); var pump = require('pump'); var match = require('anymatch');var _require = require('beaker-error-constants'),ArchiveNotWritableError = _require.ArchiveNotWritableError,SourceNotFoundError = _require.SourceNotFoundError,DestDirectoryNotEmpty = _require.DestDirectoryNotEmpty,ParentFolderDoesntExistError = _require.ParentFolderDoesntExistError;var _require2 = require('./common'),maybe = _require2.maybe;var _require3 = require('./lookup'),stat = _require3.stat;var _require4 = require('./read'),readdir = _require4.readdir;var _require5 = require('./write'),mkdir = _require5.mkdir;var _require6 = require('./delete'),unlink = _require6.unlink,rmdir = _require6.rmdir; var DEFAULT_IGNORE = ['.dat', '**/.dat', '.git', '**/.git']; // copy files from the filesystem into an archive function exportFilesystemToArchive(opts, cb) { return maybe(cb, _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {var srcPath, dstArchive, dstPath, ignore, inplaceImport, dryRun, srcStat, dstStat, statThenExport, exportFile, exportDirectory, stats;return regeneratorRuntime.wrap(function _callee4$(_context4) {while (1) {switch (_context4.prev = _context4.next) {case 0: assert(opts && typeof opts === 'object', 'opts object is required'); // core arguments, srcPath and dstArchive srcPath = opts.srcPath; dstArchive = opts.dstArchive; assert(srcPath && typeof srcPath === 'string', 'srcPath is required'); assert(dstArchive && typeof dstArchive === 'object', 'dstArchive is required'); // options dstPath = typeof opts.dstPath === 'string' ? opts.dstPath : '/'; ignore = Array.isArray(opts.ignore) ? opts.ignore : DEFAULT_IGNORE; inplaceImport = opts.inplaceImport === true; dryRun = opts.dryRun === true; // ensure we have the archive's private key if (!(!dstArchive.writable && !dryRun)) {_context4.next = 11;break;}throw ( new ArchiveNotWritableError());case 11:_context4.prev = 11;_context4.next = 14;return ( fse.stat(srcPath));case 14:srcStat = _context4.sent;_context4.next = 20;break;case 17:_context4.prev = 17;_context4.t0 = _context4['catch'](11);throw ( new SourceNotFoundError(_context4.t0.toString()));case 20: // if reading from a directory, and not doing an implace-import, // then put the dstPath at a subpath so that the folder's contents dont // get imported in-place into the archive if (srcStat.isDirectory() && !inplaceImport) { dstPath = path.join(dstPath, path.basename(srcPath)); } // make sure the destination is a folder _context4.prev = 21;_context4.next = 24;return ( stat(dstArchive, dstPath));case 24:dstStat = _context4.sent;_context4.next = 29;break;case 27:_context4.prev = 27;_context4.t1 = _context4['catch'](21);case 29:if ( dstStat) {_context4.next = 38;break;}_context4.prev = 30;_context4.next = 33;return ( stat(dstArchive, path.dirname(dstPath)));case 33:dstStat = _context4.sent;_context4.next = 38;break;case 36:_context4.prev = 36;_context4.t2 = _context4['catch'](30);case 38:if (!( !dstStat || !dstStat.isDirectory())) {_context4.next = 40;break;}throw ( new ParentFolderDoesntExistError());case 40: // dont overwrite directories with files if (!srcStat.isDirectory() && dstStat.isDirectory()) { dstPath = path.join(dstPath, path.basename(srcPath)); } statThenExport = function () {var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(srcPath, dstPath) {var srcStat;return regeneratorRuntime.wrap(function _callee$(_context) {while (1) {switch (_context.prev = _context.next) {case 0:if (!( ignore && match(ignore, srcPath))) {_context.next = 2;break;}return _context.abrupt('return');case 2:_context.next = 4;return ( fse.stat(srcPath));case 4:srcStat = _context.sent;if (! srcStat.isFile()) {_context.next = 10;break;}_context.next = 8;return ( exportFile(srcPath, srcStat, dstPath));case 8:_context.next = 13;break;case 10:if (! srcStat.isDirectory()) {_context.next = 13;break;}_context.next = 13;return ( exportDirectory(srcPath, dstPath));case 13:case 'end':return _context.stop();}}}, _callee, this);}));return function statThenExport(_x, _x2) {return _ref2.apply(this, arguments);};}(); exportFile = function () {var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(srcPath, srcStat, dstPath) {var dstFileStats;return regeneratorRuntime.wrap(function _callee2$(_context2) {while (1) {switch (_context2.prev = _context2.next) {case 0: // fetch dest stats dstFileStats = null;_context2.prev = 1;_context2.next = 4;return ( stat(dstArchive, dstPath));case 4:dstFileStats = _context2.sent;_context2.next = 9;break;case 7:_context2.prev = 7;_context2.t0 = _context2['catch'](1);case 9: // track the stats stats.fileCount++; stats.totalSize += srcStat.size || 0;if (! dstFileStats) {_context2.next = 23;break;}if (! dstFileStats.isDirectory()) {_context2.next = 20;break;}if ( dryRun) {_context2.next = 16;break;}_context2.next = 16;return rmdir(dstArchive, dstPath, { recursive: true });case 16: stats.removedFolders.push(dstPath); stats.addedFiles.push(dstPath);_context2.next = 21;break;case 20: stats.updatedFiles.push(dstPath);case 21:_context2.next = 24;break;case 23: stats.addedFiles.push(dstPath);case 24:if (! dryRun) {_context2.next = 26;break;}return _context2.abrupt('return');case 26:return _context2.abrupt('return', new Promise(function (resolve, reject) { pump( fse.createReadStream(srcPath), dstArchive.createWriteStream(dstPath), function (err) { if (err) reject(err);else resolve(); }); }));case 27:case 'end':return _context2.stop();}}}, _callee2, this, [[1, 7]]);}));return function exportFile(_x3, _x4, _x5) {return _ref3.apply(this, arguments);};}(); exportDirectory = function () {var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(srcPath, dstPath) {var dstStat, fileNames, promises;return regeneratorRuntime.wrap(function _callee3$(_context3) {while (1) {switch (_context3.prev = _context3.next) {case 0:_context3.prev = 0;_context3.next = 3;return ( stat(dstArchive, dstPath));case 3:dstStat = _context3.sent;_context3.next = 8;break;case 6:_context3.prev = 6;_context3.t0 = _context3['catch'](0);case 8:if ( dstStat) {_context3.next = 15;break;}if ( dryRun) {_context3.next = 12;break;}_context3.next = 12;return mkdir(dstArchive, dstPath);case 12: stats.addedFolders.push(dstPath);_context3.next = 25;break;case 15:if (! dstStat.isFile()) {_context3.next = 25;break;}if ( dryRun) {_context3.next = 21;break;}_context3.next = 19;return ( unlink(dstArchive, dstPath));case 19:_context3.next = 21;return ( mkdir(dstArchive, dstPath));case 21: stats.addedFolders.push(dstPath); stats.removedFiles.push(dstPath);if (! dryRun) {_context3.next = 25;break;}return _context3.abrupt('return');case 25:_context3.next = 27;return ( fse.readdir(srcPath));case 27:fileNames = _context3.sent; // recurse into each promises = fileNames.map(function (name) { return statThenExport(path.join(srcPath, name), path.join(dstPath, name)); });_context3.next = 31;return ( Promise.all(promises));case 31:case 'end':return _context3.stop();}}}, _callee3, this, [[0, 6]]);}));return function exportDirectory(_x6, _x7) {return _ref4.apply(this, arguments);};}(); // recursively export stats = { addedFiles: [], addedFolders: [], updatedFiles: [], removedFiles: [], removedFolders: [], skipCount: 0, fileCount: 0, totalSize: 0 };_context4.next = 47;return ( statThenExport(srcPath, dstPath));case 47:return _context4.abrupt('return', stats);case 48:case 'end':return _context4.stop();}}}, _callee4, this, [[11, 17], [21, 27], [30, 36]]);}))); } // copy files from an archive into the filesystem function exportArchiveToFilesystem(opts, cb) { return maybe(cb, _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8() {var srcArchive, dstPath, srcPath, overwriteExisting, skipUndownloadedFiles, ignore, files, statThenExport, exportFile, exportDirectory, stats;return regeneratorRuntime.wrap(function _callee8$(_context8) {while (1) {switch (_context8.prev = _context8.next) {case 0: assert(opts && typeof opts === 'object', 'opts object is required'); // core arguments, dstPath and srcArchive srcArchive = opts.srcArchive; dstPath = opts.dstPath; assert(srcArchive && typeof srcArchive === 'object', 'srcArchive is required'); assert(dstPath && typeof dstPath === 'string', 'dstPath is required'); // options srcPath = typeof opts.srcPath === 'string' ? opts.srcPath : '/'; overwriteExisting = opts.overwriteExisting === true; skipUndownloadedFiles = opts.skipUndownloadedFiles === true; ignore = Array.isArray(opts.ignore) ? opts.ignore : DEFAULT_IGNORE; // abort if nonempty and not overwriting existing if (overwriteExisting) {_context8.next = 21;break;} files = void 0;_context8.prev = 11;_context8.next = 14;return ( fse.readdir(dstPath));case 14:files = _context8.sent;_context8.next = 19;break;case 17:_context8.prev = 17;_context8.t0 = _context8['catch'](11);case 19:if (!( files && files.length > 0)) {_context8.next = 21;break;}throw ( new DestDirectoryNotEmpty());case 21: statThenExport = function () {var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5(srcPath, dstPath) {var srcStat;return regeneratorRuntime.wrap(function _callee5$(_context5) {while (1) {switch (_context5.prev = _context5.next) {case 0:if (!( ignore && match(ignore, srcPath))) {_context5.next = 2;break;}return _context5.abrupt('return');case 2:_context5.next = 4;return ( stat(srcArchive, srcPath));case 4:srcStat = _context5.sent;if (! srcStat.isFile()) {_context5.next = 10;break;}_context5.next = 8;return ( exportFile(srcPath, srcStat, dstPath));case 8:_context5.next = 13;break;case 10:if (! srcStat.isDirectory()) {_context5.next = 13;break;}_context5.next = 13;return ( exportDirectory(srcPath, dstPath));case 13:case 'end':return _context5.stop();}}}, _callee5, this);}));return function statThenExport(_x8, _x9) {return _ref6.apply(this, arguments);};}(); exportFile = function () {var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6(srcPath, srcStat, dstPath) {var dstFileStats;return regeneratorRuntime.wrap(function _callee6$(_context6) {while (1) {switch (_context6.prev = _context6.next) {case 0:if (!( skipUndownloadedFiles && srcStat.downloaded < srcStat.blocks)) {_context6.next = 2;break;}return _context6.abrupt('return');case 2: // fetch dest stats dstFileStats = null;_context6.prev = 3;_context6.next = 6;return ( fse.stat(dstPath));case 6:dstFileStats = _context6.sent;_context6.next = 11;break;case 9:_context6.prev = 9;_context6.t0 = _context6['catch'](3);case 11: // track the stats stats.fileCount++; stats.totalSize += srcStat.size || 0;if (! dstFileStats) {_context6.next = 23;break;}if (! dstFileStats.isDirectory()) {_context6.next = 20;break;}_context6.next = 17;return ( fse.remove(dstPath));case 17: stats.addedFiles.push(dstPath);_context6.next = 21;break;case 20: stats.updatedFiles.push(dstPath);case 21:_context6.next = 24;break;case 23: stats.addedFiles.push(dstPath);case 24:return _context6.abrupt('return', new Promise(function (resolve, reject) { pump( srcArchive.createReadStream(srcPath), fse.createWriteStream(dstPath), function (err) { if (err) reject(err);else resolve(); }); }));case 25:case 'end':return _context6.stop();}}}, _callee6, this, [[3, 9]]);}));return function exportFile(_x10, _x11, _x12) {return _ref7.apply(this, arguments);};}(); exportDirectory = function () {var _ref8 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7(srcPath, dstPath) {var fileNames, promises;return regeneratorRuntime.wrap(function _callee7$(_context7) {while (1) {switch (_context7.prev = _context7.next) {case 0:_context7.next = 2;return ( fse.ensureDir(dstPath));case 2:_context7.next = 4;return ( readdir(srcArchive, srcPath));case 4:fileNames = _context7.sent; // recurse into each promises = fileNames.map(function (name) { return statThenExport(path.join(srcPath, name), path.join(dstPath, name)); });_context7.next = 8;return ( Promise.all(promises));case 8:case 'end':return _context7.stop();}}}, _callee7, this);}));return function exportDirectory(_x13, _x14) {return _ref8.apply(this, arguments);};}(); // recursively export stats = { addedFiles: [], updatedFiles: [], skipCount: 0, fileCount: 0, totalSize: 0 };_context8.next = 27;return ( statThenExport(srcPath, dstPath));case 27:return _context8.abrupt('return', stats);case 28:case 'end':return _context8.stop();}}}, _callee8, this, [[11, 17]]);}))); } // copy files from one archive into another function exportArchiveToArchive(opts, cb) { return maybe(cb, _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee12() {var srcArchive, dstArchive, srcPath, dstPath, skipUndownloadedFiles, ignore, dstStat, statThenExport, exportFile, exportDirectory, stats;return regeneratorRuntime.wrap(function _callee12$(_context12) {while (1) {switch (_context12.prev = _context12.next) {case 0: assert(opts && typeof opts === 'object', 'opts object is required'); // core arguments, dstArchive and srcArchive srcArchive = opts.srcArchive; dstArchive = opts.dstArchive; assert(srcArchive && typeof srcArchive === 'object', 'srcArchive is required'); assert(dstArchive && typeof dstArchive === 'object', 'dstArchive is required'); // options srcPath = typeof opts.srcPath === 'string' ? opts.srcPath : '/'; dstPath = typeof opts.dstPath === 'string' ? opts.dstPath : '/'; skipUndownloadedFiles = opts.skipUndownloadedFiles === true; ignore = Array.isArray(opts.ignore) ? opts.ignore : DEFAULT_IGNORE; // ensure we have the archive's private key if (dstArchive.writable) {_context12.next = 11;break;}throw ( new ArchiveNotWritableError());case 11:_context12.prev = 11;_context12.next = 14;return ( stat(dstArchive, dstPath));case 14:dstStat = _context12.sent;_context12.next = 19;break;case 17:_context12.prev = 17;_context12.t0 = _context12['catch'](11);case 19:if ( dstStat) {_context12.next = 28;break;}_context12.prev = 20;_context12.next = 23;return ( stat(dstArchive, path.dirname(dstPath)));case 23:dstStat = _context12.sent;_context12.next = 28;break;case 26:_context12.prev = 26;_context12.t1 = _context12['catch'](20);case 28:if (!( !dstStat || !dstStat.isDirectory())) {_context12.next = 30;break;}throw ( new ParentFolderDoesntExistError());case 30: statThenExport = function () {var _ref10 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9(srcPath, dstPath) {var srcStat;return regeneratorRuntime.wrap(function _callee9$(_context9) {while (1) {switch (_context9.prev = _context9.next) {case 0:if (!( ignore && match(ignore, srcPath))) {_context9.next = 2;break;}return _context9.abrupt('return');case 2:_context9.next = 4;return ( stat(srcArchive, srcPath));case 4:srcStat = _context9.sent;if (! srcStat.isFile()) {_context9.next = 10;break;}_context9.next = 8;return ( exportFile(srcPath, srcStat, dstPath));case 8:_context9.next = 13;break;case 10:if (! srcStat.isDirectory()) {_context9.next = 13;break;}_context9.next = 13;return ( exportDirectory(srcPath, dstPath));case 13:case 'end':return _context9.stop();}}}, _callee9, this);}));return function statThenExport(_x15, _x16) {return _ref10.apply(this, arguments);};}(); exportFile = function () {var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee10(srcPath, srcStat, dstPath) {var dstFileStats;return regeneratorRuntime.wrap(function _callee10$(_context10) {while (1) {switch (_context10.prev = _context10.next) {case 0:if (!( skipUndownloadedFiles && srcStat.downloaded < srcStat.blocks)) {_context10.next = 2;break;}return _context10.abrupt('return');case 2: // fetch dest stats dstFileStats = null;_context10.prev = 3;_context10.next = 6;return ( stat(dstArchive, dstPath));case 6:dstFileStats = _context10.sent;_context10.next = 11;break;case 9:_context10.prev = 9;_context10.t0 = _context10['catch'](3);case 11: // track the stats stats.fileCount++; stats.totalSize += srcStat.size || 0;if (! dstFileStats) {_context10.next = 23;break;}if (! dstFileStats.isDirectory()) {_context10.next = 20;break;}_context10.next = 17;return ( rmdir(dstArchive, dstPath, { recursive: true }));case 17: stats.addedFiles.push(dstPath);_context10.next = 21;break;case 20: stats.updatedFiles.push(dstPath);case 21:_context10.next = 24;break;case 23: stats.addedFiles.push(dstPath);case 24:return _context10.abrupt('return', new Promise(function (resolve, reject) { pump( srcArchive.createReadStream(srcPath), dstArchive.createWriteStream(dstPath), function (err) { if (err) reject(err);else resolve(); }); }));case 25:case 'end':return _context10.stop();}}}, _callee10, this, [[3, 9]]);}));return function exportFile(_x17, _x18, _x19) {return _ref11.apply(this, arguments);};}(); exportDirectory = function () {var _ref12 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee11(srcPath, dstPath) {var dstStat, fileNames, promises;return regeneratorRuntime.wrap(function _callee11$(_context11) {while (1) {switch (_context11.prev = _context11.next) {case 0:_context11.prev = 0;_context11.next = 3;return ( stat(dstArchive, dstPath));case 3:dstStat = _context11.sent;_context11.next = 8;break;case 6:_context11.prev = 6;_context11.t0 = _context11['catch'](0);case 8:if ( dstStat) {_context11.next = 13;break;}_context11.next = 11;return ( mkdir(dstArchive, dstPath));case 11:_context11.next = 18;break;case 13:if (! dstStat.isFile()) {_context11.next = 18;break;}_context11.next = 16;return ( unlink(dstArchive, dstPath));case 16:_context11.next = 18;return ( mkdir(dstArchive, dstPath));case 18:_context11.next = 20;return ( readdir(srcArchive, srcPath));case 20:fileNames = _context11.sent; // recurse into each promises = fileNames.map(function (name) { return statThenExport(path.join(srcPath, name), path.join(dstPath, name)); });_context11.next = 24;return ( Promise.all(promises));case 24:case 'end':return _context11.stop();}}}, _callee11, this, [[0, 6]]);}));return function exportDirectory(_x20, _x21) {return _ref12.apply(this, arguments);};}(); // recursively export stats = { addedFiles: [], updatedFiles: [], skipCount: 0, fileCount: 0, totalSize: 0 };_context12.next = 36;return ( statThenExport(srcPath, dstPath));case 36:return _context12.abrupt('return', stats);case 37:case 'end':return _context12.stop();}}}, _callee12, this, [[11, 17], [20, 26]]);}))); } module.exports = { exportFilesystemToArchive, exportArchiveToFilesystem, exportArchiveToArchive };