├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── appveyor.yml ├── examples ├── callback.js ├── collection.js ├── tar.js └── web_stream.js ├── index.js ├── index.min.js ├── package-lock.json ├── package.json └── test ├── data.js ├── error.js ├── issue10.js ├── parser.js ├── stream.js └── structure.js /.gitignore: -------------------------------------------------------------------------------- 1 | # OS and Ide 2 | .DS_Store 3 | .project 4 | .settings 5 | 6 | # Logs 7 | *.log 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov/ 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage/ 19 | tmp/ 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/ 26 | 27 | # Dependency directory 28 | # Deployed apps should consider commenting this line out: 29 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 30 | node_modules/ 31 | bower_components/ 32 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Env configuration 2 | .* 3 | *.yml 4 | Gruntfile.js 5 | bower.json 6 | 7 | # Logs 8 | *.log 9 | 10 | # Coverage directory used by tools like istanbul 11 | coverage/ 12 | tmp/ 13 | 14 | # Repository directory 15 | examples/ 16 | test/ 17 | 18 | # Dependency directory 19 | # Deployed apps should consider commenting this line out: 20 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 21 | node_modules/ 22 | bower_components/ 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "4" 5 | - "5" 6 | - "6" 7 | - "7" 8 | - "8" 9 | - "9" 10 | matrix: 11 | include: 12 | - node_js: "10" 13 | env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" 14 | allow_failures: 15 | - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" 16 | os: 17 | - linux 18 | cache: 19 | directories: 20 | - node_modules 21 | before_install: 22 | - "test ! -d node_modules || npm prune" 23 | - "test ! -d node_modules || npm rebuild" 24 | script: "npm run-script test-cov" 25 | after_script: "npm i coveralls@~3 && cat ./coverage/lcov.info | coveralls" 26 | notifications: 27 | email: 28 | on_success: never 29 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v1.6.9 / 2016-12-13 2 | ================== 3 | 4 | * Update `bson`@1.0.1 5 | * Update `mongodb`@2.2.16 6 | * Update `graceful-fs`@4.1.11 7 | * Update `logger-request`@3.7.3 8 | 9 | v1.6.8 / 2016-11-08 10 | ================== 11 | 12 | * Remove support for `node`@0 13 | * Update `graceful-fs`@4.1.10 14 | * Update `logger-request`@3.7.2 15 | 16 | v1.6.7 / 2016-10-27 17 | ================== 18 | 19 | * Tested against `node`@7 20 | * Improve pathname join with node API 21 | * Prevent logger crash if err is null 22 | * Update `bson`@0.5.6 23 | * Update `mongodb`@2.2.11 24 | 25 | v1.6.6 / 2016-09-20 26 | ================== 27 | 28 | * Update `bson`@0.5.5 29 | * Update `mongodb`@2.2.10 30 | 31 | v1.6.5 / 2016-09-13 32 | ================== 33 | 34 | * Update `bson`@0.5.4 35 | * Update `mongodb`@2.2.9 36 | * Update `logger-request`@3.7.1 37 | 38 | v1.6.4 / 2016-08-21 39 | ================== 40 | 41 | * Pass `err` argument to callback function 42 | * Update `bson`@0.5.3 43 | * Update `graceful`@4.1.6 44 | * Update `mongodb`@2.2.7 45 | 46 | v1.6.3 / 2016-07-31 47 | ================== 48 | 49 | * Update `graceful-fs`@4.1.5 50 | * Update `mongodb`@2.2.5 51 | 52 | v1.6.2 / 2016-07-26 53 | ================== 54 | 55 | * Tested against `node`@6 56 | * Update `mongodb`@2.2.4 57 | 58 | v1.6.1 / 2016-07-16 59 | ================== 60 | 61 | * Install `graceful-fs`@4.1.4 for #16 62 | * Update `bson`@0.5.2 63 | * Update `mongodb`@2.2.2 64 | * Update `fstream`@1.0.10 65 | 66 | v1.6.0 / 2016-06-05 67 | ================== 68 | 69 | * Return data as Stream 70 | * Async file writer 71 | 72 | v1.5.6 / 2016-06-05 73 | ================== 74 | 75 | * Update `mongodb`@2.1.21 76 | * Update `fstream`@1.0.9 77 | 78 | v1.5.5 / 2016-04-17 79 | ================== 80 | 81 | * Change LICENSE to Apache2 from GPL3 82 | * Tested against `node`@5.x 83 | * Update `logger-request`@3.6.1 84 | * Update `bson`@0.4.23 85 | * Update `mongodb`@2.1.16 86 | 87 | v1.5.4 / 2016-02-11 88 | ================== 89 | 90 | * Update `mongodb`@2.1.7 91 | 92 | v1.5.3 / 2016-02-01 93 | ================== 94 | 95 | * Added "numCursors" (options) 96 | * Added support for `parallelCollectionScan` 97 | * Use `snapshot` when use query for retrieve data 98 | 99 | v1.5.2 / 2016-01-17 100 | ================== 101 | 102 | * Added test for Long datatype 103 | * Update `bson`@0.4.21 104 | * Update `mongodb`@2.1.4 105 | 106 | v1.5.1 / 2016-01-04 107 | ================== 108 | 109 | * Tested against `node`@5.3 110 | * Update `mongodb`@2.1.3 111 | 112 | v1.5.0 / 2015-12-29 113 | ================== 114 | 115 | * Versions 1.4.x will be release under `stable` tag 116 | * Update `mongodb`@2.1.2 117 | 118 | v1.4.4 / 2015-12-27 119 | ================== 120 | 121 | * Update `mongodb`@2.0.53 122 | 123 | v1.4.3 / 2015-12-15 124 | ================== 125 | 126 | * Tested against `node`@5 127 | * Update `logger-request`@3.6.0 128 | * Update `mongodb`@2.0.52 129 | * Update `bson`@0.4.20 130 | 131 | v1.4.2 / 2015-10-07 132 | ================== 133 | 134 | * Update `mongodb`@2.0.45 135 | * Update `bson`@0.4.16 136 | 137 | v1.4.1 / 2015-09-17 138 | ================== 139 | 140 | * Bump minor version for sync with `mongodb-restore` 141 | * Tested against `node`@4 142 | * Update `mongodb`@2.0.43 143 | * Update `fstream`@1.0.8 144 | * Update `tar`@2.2.1 145 | 146 | v1.3.0 / 2015-09-02 147 | ================== 148 | 149 | * Tested against `iojs`@3 150 | * Update `logger-request`@3.4.0 151 | * Update `mongodb`@2.0.42 152 | * Update `bson`@0.4.11 153 | * Update `tar`@2.2.0 154 | 155 | v1.2.2 / 2015-07-18 156 | ================== 157 | 158 | * Update `logger-request`@3.3.5 159 | * Update `mongodb`@2.0.39 160 | * Update `bson`@0.4.8 161 | 162 | v1.2.1 / 2015-06-20 163 | ================== 164 | 165 | * SPDX license 166 | * Update `logger-request`@3.3.4 167 | * Update `mongodb`@2.0.34 168 | * Update `fstream`@1.0.7 169 | 170 | v1.2.0 / 2015-05-12 171 | ================== 172 | 173 | * Tested against `iojs`@2 174 | * Update `tar`@2.1.1 175 | * Update `logger-request`@3.3.3 176 | * Update `bson`@0.3.2 177 | * Update `mongodb`@2.0.31 178 | * Update `fstream`@1.0.6 179 | 180 | v1.1.1 / 2015-04-12 181 | ================== 182 | 183 | * Update `tar`@2.0.1 184 | * Update `logger-request`@3.3.2 185 | * Update `bson`@0.3.1 186 | * Update `mongodb`@2.0.27 187 | 188 | v1.1.0 / 2015-03-02 189 | ================== 190 | 191 | * Add "stream" (options) 192 | * `coveralls` test 193 | * Update `logger-request`@3.3.1 194 | * Update `bson`@0.2.19 195 | * Update `mongodb`@2.0.18 196 | 197 | v1.0.2 / 2015-02-06 198 | ================== 199 | 200 | * `windows` test 201 | * `iojs` test 202 | * Update `logger-request`@3.2.8 203 | * Update `bson`@0.2.18 204 | * Update `fstream`@1.0.4 205 | * Update `mongodb`@2.0.15 206 | 207 | v1.0.1 / 2015-01-03 208 | ================== 209 | 210 | * Remove json formatter from logger 211 | * Update `logger-request`@3.2.7 212 | 213 | v1.0.0 / 2014-12-27 214 | ================== 215 | 216 | * Use mongodb logger 217 | * Use `mongodb` 2 218 | * Add "options" (options) 219 | 220 | v0.2.0 / 2014-12-27 221 | ================== 222 | 223 | * Add custom parser 224 | 225 | v0.1.2 / 2014-12-26 226 | ================== 227 | 228 | * Update documentation 229 | 230 | v0.1.1 / 2014-12-26 231 | ================== 232 | 233 | * `callback` control 234 | * "root" control 235 | 236 | v0.1.0 / 2014-12-25 237 | ================== 238 | 239 | * Update `logger-request`@3.2.5 240 | * Add "metadata" (options) 241 | 242 | v0.0.6 / 2014-12-22 243 | ================== 244 | 245 | * Update `logger-request`@3.2.4 246 | * Update `mongodb`@1.4.26 247 | 248 | v0.0.5 / 2014-12-18 249 | ================== 250 | 251 | * Update `bson`@0.2.16 252 | 253 | v0.0.4 / 2014-12-08 254 | ================== 255 | 256 | * Update `mongodb`@1.4.23 257 | 258 | v0.0.3 / 2014-12-06 259 | ================== 260 | 261 | * Fix bug when empty docs or collections 262 | * Fix bug when missing dir of tarfile 263 | * Fix bug on callback after tar packer 264 | 265 | v0.0.2 / 2014-12-06 266 | ================== 267 | 268 | * Logger integration 269 | * Add "query" (options) 270 | 271 | v0.0.1 / 2014-12-05 272 | ================== 273 | 274 | * Project ready 275 | 276 | v0.0.0 / 2014-12-05 277 | ================== 278 | 279 | * Project start 280 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file gruntfile 4 | * @subpackage main 5 | * @version 0.0.1 6 | * @author hex7c0 7 | * @copyright hex7c0 2015 8 | * @license GPLv3 9 | */ 10 | 11 | module.exports = function(grunt) { 12 | 13 | grunt.initConfig({ 14 | pkg: grunt.file.readJSON('package.json'), 15 | banner: '/*\n' + ' * <%= pkg.name %> v<%= pkg.version %>\n' 16 | + ' * (c) <%= pkg.author.name %> <%= pkg.homepage %>\n' 17 | + ' * Licensed under <%= pkg.license %>\n' + ' */\n', 18 | 19 | clean: [ 'index.min.js', 'min/**/*.js' ], 20 | 21 | uglify: { 22 | target: { 23 | options: { 24 | mangle: false, 25 | beautify: true 26 | }, 27 | files: [ { 28 | expand: true, 29 | src: 'lib/**/*.js', 30 | dest: 'min' 31 | }, { 32 | expand: true, 33 | src: 'module/**/*.js', 34 | dest: 'min' 35 | }, { 36 | 'index.min.js': 'index.js' 37 | } ] 38 | } 39 | }, 40 | 41 | jshint: { 42 | options: { 43 | curly: true, 44 | indent: 2, 45 | quotmark: 'single', 46 | undef: true, 47 | unused: true, 48 | strict: true, 49 | node: true, 50 | // relax 51 | laxbreak: true, 52 | loopfunc: true, 53 | shadow: true 54 | }, 55 | target: { 56 | src: [ 'lib/**/*.js', 'module/**/*.js', 'index.js' ] 57 | } 58 | }, 59 | 60 | shell: { 61 | options: { 62 | failOnError: false 63 | }, 64 | docs: { 65 | command: 'jsdoc ./lib/*.js ./module/*.js -c .jsdoc.json' 66 | } 67 | }, 68 | 69 | safer: { 70 | target: { 71 | files: [ { 72 | src: 'lib/**/*.js' 73 | }, { 74 | src: 'module/**/*.js' 75 | }, { 76 | src: 'index.js', 77 | } ] 78 | } 79 | }, 80 | 81 | endline: { 82 | target: { 83 | files: [ { 84 | src: 'lib/**/*.js' 85 | }, { 86 | src: 'min/**/*.js' 87 | }, { 88 | src: 'module/**/*.js' 89 | }, { 90 | src: '*.js', 91 | } ] 92 | } 93 | } 94 | }); 95 | 96 | grunt.loadNpmTasks('grunt-contrib-uglify'); 97 | grunt.loadNpmTasks('grunt-contrib-jshint'); 98 | grunt.loadNpmTasks('grunt-endline'); 99 | grunt.loadNpmTasks('grunt-safer-regex'); 100 | 101 | grunt.registerTask('lint', [ 'jshint', 'safer' ]); 102 | grunt.registerTask('min', [ 'uglify', 'endline' ]); 103 | grunt.registerTask('default', [ 'lint', 'min' ]); 104 | 105 | return; 106 | }; 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [mongodb-backup](https://github.com/hex7c0/mongodb-backup) 2 | 3 | [![NPM version](https://img.shields.io/npm/v/mongodb-backup.svg)](https://www.npmjs.com/package/mongodb-backup) 4 | [![Linux Status](https://img.shields.io/travis/hex7c0/mongodb-backup.svg?label=linux)](https://travis-ci.org/hex7c0/mongodb-backup) 5 | [![Windows Status](https://img.shields.io/appveyor/ci/hex7c0/mongodb-backup.svg?label=windows)](https://ci.appveyor.com/project/hex7c0/mongodb-backup) 6 | [![Dependency Status](https://img.shields.io/david/hex7c0/mongodb-backup.svg)](https://david-dm.org/hex7c0/mongodb-backup) 7 | [![Coveralls](https://img.shields.io/coveralls/hex7c0/mongodb-backup.svg)](https://coveralls.io/r/hex7c0/mongodb-backup) 8 | 9 | Backup for mongodb 10 | 11 | Look at [`mongodb-backup-cli`](https://github.com/hex7c0/mongodb-backup-cli) for command line usage, similar to [mongodump](http://docs.mongodb.org/manual/reference/program/mongodump/) 12 | 13 | Look at [`mongodb-restore`](https://github.com/hex7c0/mongodb-restore) for restore data 14 | 15 | ## Installation 16 | 17 | Install through NPM 18 | 19 | ```bash 20 | npm install mongodb-backup 21 | ``` 22 | or 23 | ```bash 24 | git clone git://github.com/hex7c0/mongodb-backup.git 25 | ``` 26 | 27 | Bson@0.4.11 has been pulled out, so versions >= `1.3.0` and <= `1.4.1` are deprecated 28 | 29 | ## API 30 | 31 | inside nodejs project 32 | ```js 33 | var backup = require('mongodb-backup'); 34 | 35 | backup({ 36 | uri: 'uri', // mongodb://:@.mongolab.com:/ 37 | root: __dirname 38 | }); 39 | ``` 40 | 41 | ### backup(options) 42 | 43 | #### options 44 | 45 | - `uri` - **String** [URI](http://mongodb.github.io/node-mongodb-native/2.0/tutorials/urls/) for MongoDb connection *(default "required")* 46 | - `root`- **String** Path where save data *(default "required")* 47 | - `[parser]` - **String | Function** Data parser (bson, json) or custom *(default "bson")* 48 | - `[collections]` - **Array** Select which collections save *(default "disabled")* 49 | - `[callback]` - **Function** Callback when done *(default "disabled")* 50 | - `[stream]`- **Object** Send `.tar` file to Node stream *(default "disabled")* 51 | - `[tar]` - **String** Pack files into a .tar file *(default "disabled")* 52 | - `[query]` - **Object** Query that optionally limits the documents included *(default "{}")* 53 | - `[numCursors]` - **Number** Set number of cursor for [parallelCollectionScan](https://docs.mongodb.org/v3.0/reference/command/parallelCollectionScan) without query *(default "disabled")* 54 | - `[logger]` - **String** Path where save a .log file *(default "disabled")* 55 | - `[metadata]` - **Boolean** Save metadata of collections as Index, ecc *(default "false")* 56 | - `[options]` - **Object** MongoDb [options](http://mongodb.github.io/node-mongodb-native/2.0/tutorials/connecting/#toc_7) *(default)* 57 | 58 | ## Examples 59 | 60 | Take a look at my [examples](https://github.com/hex7c0/mongodb-backup/tree/1.6/examples) 61 | 62 | ### [License Apache2](https://github.com/hex7c0/mongodb-backup/blob/1.6/LICENSE) 63 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: "4" 4 | - nodejs_version: "5" 5 | - nodejs_version: "6" 6 | - nodejs_version: "7" 7 | - nodejs_version: "8" 8 | - nodejs_version: "9" 9 | cache: 10 | - node_modules 11 | install: 12 | - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) 13 | - if exist node_modules npm prune 14 | - if exist node_modules npm rebuild 15 | - npm install 16 | build: off 17 | test_script: 18 | - node --version 19 | - npm --version 20 | - npm test 21 | version: "{build}" 22 | -------------------------------------------------------------------------------- /examples/callback.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file callback example 4 | * @module mongodb-backup 5 | * @subpackage examples 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); // use require('mongodb-backup') instead 15 | 16 | /* 17 | * use 18 | */ 19 | backup({ 20 | uri: 'uri', // mongodb://:@.mongolab.com:/ 21 | root: __dirname, // write files into this dir 22 | callback: function(err) { 23 | 24 | if (err) { 25 | console.error(err); 26 | } else { 27 | console.log('finish'); 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /examples/collection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file collection example 4 | * @module mongodb-backup 5 | * @subpackage examples 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); // use require('mongodb-backup') instead 15 | 16 | /* 17 | * use 18 | */ 19 | backup({ 20 | uri: 'uri', // mongodb://:@.mongolab.com:/ 21 | root: __dirname, // write files into this dir 22 | collections: [ 'logins' ], // save this collection only 23 | }); 24 | -------------------------------------------------------------------------------- /examples/tar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file tar example 4 | * @module mongodb-backup 5 | * @subpackage examples 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); // use require('mongodb-backup') instead 15 | 16 | /* 17 | * use 18 | */ 19 | backup({ 20 | uri: 'uri', // mongodb://:@.mongolab.com:/ 21 | root: __dirname, // write files into this dir 22 | collections: [ 'logins' ], // save this collection only 23 | tar: 'dump.tar', // save backup into this tar file 24 | }); 25 | -------------------------------------------------------------------------------- /examples/web_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file web stream example 4 | * @module mongodb-backup 5 | * @subpackage examples 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); // use require('mongodb-backup') instead 15 | 16 | /* 17 | * use 18 | */ 19 | var http = require('http'); 20 | http.createServer(function(req, res) { 21 | 22 | res.writeHead(200, { 23 | 'Content-Type': 'application/x-tar' // force header for tar download 24 | }); 25 | 26 | backup({ 27 | uri: 'uri', // mongodb://:@.mongolab.com:/ 28 | collections: [ 'logins' ], // save this collection only 29 | stream: res, // send stream into client response 30 | }); 31 | }).listen(3000); 32 | console.log('Server running at http://127.0.0.1:3000/'); 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file mongodb-backup main 4 | * @module mongodb-backup 5 | * @subpackage main 6 | * @version 1.6.0 7 | * @author hex7c0 8 | * @copyright hex7c0 2014 9 | * @license GPLv3 10 | */ 11 | 12 | /* 13 | * initialize module 14 | */ 15 | var systemRegex = /^system\./; 16 | var fs = require('graceful-fs'); 17 | var path = require('path'); 18 | var BSON; 19 | var logger; 20 | var meta; 21 | 22 | /* 23 | * functions 24 | */ 25 | /** 26 | * error handler 27 | * 28 | * @function error 29 | * @param {Object} err - raised error 30 | */ 31 | function error(err) { 32 | 33 | if (err) { 34 | logger(err.message); 35 | } 36 | } 37 | 38 | /** 39 | * save collection metadata to file 40 | * 41 | * @function writeMetadata 42 | * @param {Object} collection - db collection 43 | * @param {String} metadata - path of metadata 44 | * @param {Function} next - callback 45 | */ 46 | function writeMetadata(collection, metadata, next) { 47 | 48 | return collection.indexes(function(err, indexes) { 49 | 50 | if (err) { 51 | return next(err); 52 | } 53 | 54 | fs.writeFile(metadata + collection.collectionName, JSON.stringify(indexes), 55 | next); 56 | }); 57 | } 58 | 59 | /** 60 | * make dir 61 | * 62 | * @function makeDir 63 | * @param {String} pathname - pathname of dir 64 | * @param {Function} next - callback 65 | */ 66 | function makeDir(pathname, next) { 67 | 68 | fs.stat(pathname, function(err, stats) { 69 | 70 | if (err && err.code === 'ENOENT') { // no file or dir 71 | logger('make dir at ' + pathname); 72 | return fs.mkdir(pathname, function(err) { 73 | 74 | next(err, pathname); 75 | }); 76 | 77 | } else if (stats && stats.isDirectory() === false) { // pathname is a file 78 | logger('unlink file at ' + pathname); 79 | return fs.unlink(pathname, function(err) { 80 | 81 | if (err) { // unlink fail. permission maybe 82 | return next(err); 83 | } 84 | 85 | logger('make dir at ' + pathname); 86 | fs.mkdir(pathname, function(err) { 87 | 88 | next(err, pathname); 89 | }); 90 | }); 91 | 92 | } else { // already a dir 93 | next(null, pathname); 94 | } 95 | }); 96 | } 97 | 98 | /** 99 | * remove dir 100 | * 101 | * @function rmDir 102 | * @param {String} pathname - path of dir 103 | * @param {Function} [next] - callback 104 | */ 105 | function rmDir(pathname, next) { 106 | 107 | fs.readdirSync(pathname).forEach(function(first) { // database 108 | 109 | var database = pathname + first; 110 | if (fs.statSync(database).isDirectory() === false) { 111 | return next(Error('path is not a Directory')); 112 | } 113 | 114 | var metadata = ''; 115 | var collections = fs.readdirSync(database); 116 | var metadataPath = path.join(database, '.metadata'); 117 | if (fs.existsSync(metadataPath) === true) { 118 | metadata = metadataPath + path.sep; 119 | delete collections[collections.indexOf('.metadata')]; // undefined is not a dir 120 | } 121 | 122 | collections.forEach(function(second) { // collection 123 | 124 | var collection = path.join(database, second); 125 | if (fs.statSync(collection).isDirectory() === false) { 126 | return; 127 | } 128 | 129 | fs.readdirSync(collection).forEach(function(third) { // document 130 | 131 | var document = path.join(collection, third); 132 | fs.unlinkSync(document); 133 | return next ? next(null, document) : ''; 134 | }); 135 | 136 | if (metadata !== '') { 137 | fs.unlinkSync(metadata + second); 138 | } 139 | fs.rmdirSync(collection); 140 | }); 141 | 142 | if (metadata !== '') { 143 | fs.rmdirSync(metadata); 144 | } 145 | return fs.rmdirSync(database); 146 | }); 147 | } 148 | 149 | /** 150 | * JSON parser async 151 | * 152 | * @function toJson 153 | * @param {Objecy} doc - document from stream 154 | * @param {String} collectionPath - path of collection 155 | */ 156 | function toJsonAsync(doc, collectionPath) { 157 | 158 | fs.writeFile(collectionPath + doc._id + '.json', JSON.stringify(doc)); 159 | } 160 | 161 | /** 162 | * BSON parser async 163 | * 164 | * @function toBson 165 | * @param {Objecy} doc - document from stream 166 | * @param {String} collectionPath - path of collection 167 | */ 168 | function toBsonAsync(doc, collectionPath) { 169 | 170 | fs.writeFile(collectionPath + doc._id + '.bson', BSON.serialize(doc)); 171 | } 172 | 173 | /** 174 | * get data from all available collections 175 | * 176 | * @function allCollections 177 | * @param {Object} db - database 178 | * @param {String} name - path of dir 179 | * @param {Object} query - find query 180 | * @param {String} metadata - path of metadata 181 | * @param {Function} parser - data parser 182 | * @param {Function} next - callback 183 | */ 184 | function allCollections(db, name, query, metadata, parser, next) { 185 | 186 | return db.collections(function(err, collections) { 187 | 188 | if (err) { 189 | return next(err); 190 | } 191 | 192 | var last = ~~collections.length, index = 0; 193 | if (last === 0) { // empty set 194 | return next(err); 195 | } 196 | 197 | collections.forEach(function(collection) { 198 | 199 | if (systemRegex.test(collection.collectionName) === true) { 200 | return last === ++index ? next(null) : null; 201 | } 202 | 203 | logger('select collection ' + collection.collectionName); 204 | makeDir(name + collection.collectionName + path.sep, function(err, name) { 205 | 206 | if (err) { 207 | return last === ++index ? next(err) : error(err); 208 | } 209 | 210 | meta(collection, metadata, function() { 211 | 212 | var stream = collection.find(query).snapshot(true).stream(); 213 | 214 | stream.once('end', function() { 215 | 216 | return last === ++index ? next(null) : null; 217 | }).on('data', function(doc) { 218 | 219 | parser(doc, name); 220 | }); 221 | }); 222 | }); 223 | }); 224 | }); 225 | } 226 | 227 | /** 228 | * get data from all available collections without query (parallelCollectionScan) 229 | * 230 | * @function allCollectionsScan 231 | * @param {Object} db - database 232 | * @param {String} name - path of dir 233 | * @param {Integer} numCursors - number of multiple cursors [1:10000] 234 | * @param {String} metadata - path of metadata 235 | * @param {Function} parser - data parser 236 | * @param {Function} next - callback 237 | */ 238 | function allCollectionsScan(db, name, numCursors, metadata, parser, next) { 239 | 240 | return db.collections(function(err, collections) { 241 | 242 | if (err) { 243 | return next(err); 244 | } 245 | 246 | var last = ~~collections.length, index = 0; 247 | if (last === 0) { // empty set 248 | return next(null); 249 | } 250 | 251 | collections.forEach(function(collection) { 252 | 253 | if (systemRegex.test(collection.collectionName) === true) { 254 | return last === ++index ? next(null) : null; 255 | } 256 | 257 | logger('select collection scan ' + collection.collectionName); 258 | makeDir(name + collection.collectionName + path.sep, function(err, name) { 259 | 260 | if (err) { 261 | return last === ++index ? next(err) : error(err); 262 | } 263 | 264 | meta(collection, metadata, function() { 265 | 266 | collection.parallelCollectionScan({ 267 | numCursors: numCursors 268 | }, function(err, cursors) { 269 | 270 | if (err) { 271 | return last === ++index ? next(err) : error(err); 272 | } 273 | 274 | var ii, cursorsDone; 275 | ii = cursorsDone = ~~cursors.length; 276 | if (ii === 0) { // empty set 277 | return last === ++index ? next(null) : null; 278 | } 279 | 280 | for (var i = 0; i < ii; ++i) { 281 | cursors[i].once('end', function() { 282 | 283 | // No more cursors let's ensure we got all results 284 | if (--cursorsDone === 0) { 285 | return last === ++index ? next(null) : null; 286 | } 287 | }).on('data', function(doc) { 288 | 289 | parser(doc, name); 290 | }); 291 | } 292 | }); 293 | }); 294 | }); 295 | }); 296 | }); 297 | } 298 | 299 | /** 300 | * get data from some collections 301 | * 302 | * @function someCollections 303 | * @param {Object} db - database 304 | * @param {String} name - path of dir 305 | * @param {Object} query - find query 306 | * @param {String} metadata - path of metadata 307 | * @param {Function} parser - data parser 308 | * @param {Function} next - callback 309 | * @param {Array} collections - selected collections 310 | */ 311 | function someCollections(db, name, query, metadata, parser, next, collections) { 312 | 313 | var last = ~~collections.length, index = 0; 314 | if (last === 0) { 315 | return next(null); 316 | } 317 | 318 | collections.forEach(function(collection) { 319 | 320 | db.collection(collection, { 321 | strict: true 322 | }, function(err, collection) { 323 | 324 | if (err) { // returns an error if the collection does not exist 325 | return last === ++index ? next(err) : error(err); 326 | } 327 | 328 | logger('select collection ' + collection.collectionName); 329 | makeDir(name + collection.collectionName + path.sep, function(err, name) { 330 | 331 | if (err) { 332 | return last === ++index ? next(err) : error(err); 333 | } 334 | 335 | meta(collection, metadata, function() { 336 | 337 | var stream = collection.find(query).snapshot(true).stream(); 338 | 339 | stream.once('end', function() { 340 | 341 | return last === ++index ? next(null) : null; 342 | }).on('data', function(doc) { 343 | 344 | parser(doc, name); 345 | }); 346 | }); 347 | }); 348 | }); 349 | }); 350 | } 351 | 352 | /** 353 | * get data from some collections without query (parallelCollectionScan) 354 | * 355 | * @function someCollectionsScan 356 | * @param {Object} db - database 357 | * @param {String} name - path of dir 358 | * @param {Integer} numCursors - number of multiple cursors [1:10000] 359 | * @param {String} metadata - path of metadata 360 | * @param {Function} parser - data parser 361 | * @param {Function} next - callback 362 | * @param {Array} collections - selected collections 363 | */ 364 | function someCollectionsScan(db, name, numCursors, metadata, parser, next, 365 | collections) { 366 | 367 | var last = ~~collections.length, index = 0; 368 | if (last === 0) { // empty set 369 | return next(null); 370 | } 371 | 372 | collections.forEach(function(collection) { 373 | 374 | db.collection(collection, { 375 | strict: true 376 | }, function(err, collection) { 377 | 378 | if (err) { // returns an error if the collection does not exist 379 | return last === ++index ? next(err) : error(err); 380 | } 381 | 382 | logger('select collection scan ' + collection.collectionName); 383 | makeDir(name + collection.collectionName + path.sep, function(err, name) { 384 | 385 | if (err) { 386 | return last === ++index ? next(err) : error(err); 387 | } 388 | 389 | meta(collection, metadata, function() { 390 | 391 | collection.parallelCollectionScan({ 392 | numCursors: numCursors 393 | }, function(err, cursors) { 394 | 395 | if (err) { 396 | return last === ++index ? next(err) : error(err); 397 | } 398 | 399 | var ii, cursorsDone; 400 | ii = cursorsDone = ~~cursors.length; 401 | if (ii === 0) { // empty set 402 | return last === ++index ? next(null) : null; 403 | } 404 | 405 | for (var i = 0; i < ii; ++i) { 406 | cursors[i].once('end', function() { 407 | 408 | // No more cursors let's ensure we got all results 409 | if (--cursorsDone === 0) { 410 | return last === ++index ? next(null) : null; 411 | } 412 | }).on('data', function(doc) { 413 | 414 | parser(doc, name); 415 | }); 416 | } 417 | }); 418 | }); 419 | }); 420 | }); 421 | }); 422 | } 423 | 424 | /** 425 | * function wrapper 426 | * 427 | * @function wrapper 428 | * @param {Object} my - parsed options 429 | */ 430 | function wrapper(my) { 431 | 432 | var parser; 433 | if (typeof my.parser === 'function') { 434 | parser = my.parser; 435 | } else { 436 | switch (my.parser.toLowerCase()) { 437 | case 'bson': 438 | BSON = require('bson'); 439 | BSON = new BSON(); 440 | parser = toBsonAsync; 441 | break; 442 | case 'json': 443 | // JSON error on ObjectId, Date and Long 444 | parser = toJsonAsync; 445 | break; 446 | default: 447 | throw new Error('missing parser option'); 448 | } 449 | } 450 | 451 | var discriminator = allCollections; 452 | if (my.collections !== null) { 453 | discriminator = someCollections; 454 | if (my.numCursors) { 455 | discriminator = someCollectionsScan; 456 | my.query = my.numCursors; // override 457 | } 458 | } else if (my.numCursors) { 459 | discriminator = allCollectionsScan; 460 | my.query = my.numCursors; // override 461 | } 462 | 463 | if (my.logger === null) { 464 | logger = function() { 465 | 466 | return; 467 | }; 468 | } else { 469 | logger = require('logger-request')({ 470 | filename: my.logger, 471 | standalone: true, 472 | daily: true, 473 | winston: { 474 | logger: '_mongo_b' + my.logger, 475 | level: 'info', 476 | json: false 477 | } 478 | }); 479 | logger('backup start'); 480 | var log = require('mongodb').Logger; 481 | log.setLevel('info'); 482 | log.setCurrentLogger(function(msg) { 483 | 484 | return logger(msg); 485 | }); 486 | } 487 | 488 | var metadata = ''; 489 | if (my.metadata === true) { 490 | meta = writeMetadata; 491 | } else { 492 | meta = function(a, b, c) { 493 | 494 | return c(); 495 | }; 496 | } 497 | 498 | /** 499 | * latest callback 500 | * 501 | * @return {Null} 502 | */ 503 | function callback(err) { 504 | 505 | logger('backup stop'); 506 | if (my.callback !== null) { 507 | logger('callback run'); 508 | my.callback(err); 509 | 510 | } else if (err) { 511 | logger(err); 512 | } 513 | } 514 | 515 | require('mongodb').MongoClient.connect(my.uri, my.options, function(err, db) { 516 | 517 | logger('db open'); 518 | if (err) { 519 | return callback(err); 520 | } 521 | 522 | var root = my.tar === null ? my.root : my.dir; 523 | makeDir(root, function(err, name) { 524 | 525 | if (err) { 526 | return callback(err); 527 | } 528 | 529 | makeDir(name + db.databaseName + path.sep, function(err, name) { 530 | 531 | function go() { 532 | 533 | // waiting for `db.fsyncLock()` on node driver 534 | return discriminator(db, name, my.query, metadata, parser, 535 | function(err) { 536 | 537 | logger('db close'); 538 | db.close(); 539 | if (err) { 540 | return callback(err); 541 | } 542 | 543 | if (my.tar) { 544 | makeDir(my.root, function(e, name) { 545 | 546 | if (err) { 547 | error(err); 548 | } 549 | 550 | var dest; 551 | if (my.stream) { // user stream 552 | logger('send tar file to stream'); 553 | dest = my.stream; 554 | } else { // filesystem stream 555 | logger('make tar file at ' + name + my.tar); 556 | dest = fs.createWriteStream(name + my.tar); 557 | } 558 | 559 | var packer = require('tar').Pack().on('error', callback).on( 560 | 'end', function() { 561 | 562 | rmDir(root); 563 | callback(null); 564 | }); 565 | 566 | require('fstream').Reader({ 567 | path: root + db.databaseName, 568 | type: 'Directory' 569 | }).on('error', callback).pipe(packer).pipe(dest); 570 | }); 571 | 572 | } else { 573 | callback(null); 574 | } 575 | }, my.collections); 576 | } 577 | 578 | if (err) { 579 | return callback(err); 580 | } 581 | 582 | if (my.metadata === false) { 583 | go(); 584 | } else { 585 | metadata = name + '.metadata' + path.sep; 586 | makeDir(metadata, go); 587 | } 588 | }); 589 | }); 590 | }); 591 | } 592 | 593 | /** 594 | * option setting 595 | * 596 | * @exports backup 597 | * @function backup 598 | * @param {Object} options - various options. Check README.md 599 | */ 600 | function backup(options) { 601 | 602 | var opt = options || Object.create(null); 603 | if (!opt.uri) { 604 | throw new Error('missing uri option'); 605 | } 606 | if (!opt.stream) { 607 | if (!opt.root) { 608 | throw new Error('missing root option'); 609 | } else if (fs.existsSync(opt.root) && !fs.statSync(opt.root).isDirectory()) { 610 | throw new Error('root option is not a directory'); 611 | } 612 | } 613 | 614 | var my = { 615 | dir: path.join(__dirname, 'dump', path.sep), 616 | uri: String(opt.uri), 617 | root: path.resolve(String(opt.root || '')) + path.sep, 618 | stream: opt.stream || null, 619 | parser: opt.parser || 'bson', 620 | numCursors: ~~opt.numCursors, 621 | collections: Array.isArray(opt.collections) ? opt.collections : null, 622 | callback: typeof (opt.callback) == 'function' ? opt.callback : null, 623 | tar: typeof opt.tar === 'string' ? opt.tar : null, 624 | query: typeof opt.query === 'object' ? opt.query : {}, 625 | logger: typeof opt.logger === 'string' ? path.resolve(opt.logger) : null, 626 | options: typeof opt.options === 'object' ? opt.options : {}, 627 | metadata: Boolean(opt.metadata) 628 | }; 629 | if (my.stream) { 630 | my.tar = true; // override 631 | } 632 | return wrapper(my); 633 | } 634 | module.exports = backup; 635 | -------------------------------------------------------------------------------- /index.min.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var BSON, logger, meta, systemRegex = /^system\./, fs = require("graceful-fs"), path = require("path"); 4 | 5 | function error(err) { 6 | err && logger(err.message); 7 | } 8 | 9 | function writeMetadata(collection, metadata, next) { 10 | return collection.indexes(function(err, indexes) { 11 | if (err) return next(err); 12 | fs.writeFile(metadata + collection.collectionName, JSON.stringify(indexes), next); 13 | }); 14 | } 15 | 16 | function makeDir(pathname, next) { 17 | fs.stat(pathname, function(err, stats) { 18 | return err && "ENOENT" === err.code ? (logger("make dir at " + pathname), fs.mkdir(pathname, function(err) { 19 | next(err, pathname); 20 | })) : stats && !1 === stats.isDirectory() ? (logger("unlink file at " + pathname), 21 | fs.unlink(pathname, function(err) { 22 | if (err) return next(err); 23 | logger("make dir at " + pathname), fs.mkdir(pathname, function(err) { 24 | next(err, pathname); 25 | }); 26 | })) : void next(null, pathname); 27 | }); 28 | } 29 | 30 | function rmDir(pathname, next) { 31 | fs.readdirSync(pathname).forEach(function(first) { 32 | var database = pathname + first; 33 | if (!1 === fs.statSync(database).isDirectory()) return next(Error("path is not a Directory")); 34 | var metadata = "", collections = fs.readdirSync(database), metadataPath = path.join(database, ".metadata"); 35 | return !0 === fs.existsSync(metadataPath) && (metadata = metadataPath + path.sep, 36 | delete collections[collections.indexOf(".metadata")]), collections.forEach(function(second) { 37 | var collection = path.join(database, second); 38 | !1 !== fs.statSync(collection).isDirectory() && (fs.readdirSync(collection).forEach(function(third) { 39 | var document = path.join(collection, third); 40 | return fs.unlinkSync(document), next ? next(null, document) : ""; 41 | }), "" !== metadata && fs.unlinkSync(metadata + second), fs.rmdirSync(collection)); 42 | }), "" !== metadata && fs.rmdirSync(metadata), fs.rmdirSync(database); 43 | }); 44 | } 45 | 46 | function toJsonAsync(doc, collectionPath) { 47 | fs.writeFile(collectionPath + doc._id + ".json", JSON.stringify(doc)); 48 | } 49 | 50 | function toBsonAsync(doc, collectionPath) { 51 | fs.writeFile(collectionPath + doc._id + ".bson", BSON.serialize(doc)); 52 | } 53 | 54 | function allCollections(db, name, query, metadata, parser, next) { 55 | return db.collections(function(err, collections) { 56 | if (err) return next(err); 57 | var last = ~~collections.length, index = 0; 58 | if (0 === last) return next(err); 59 | collections.forEach(function(collection) { 60 | if (!0 === systemRegex.test(collection.collectionName)) return last === ++index ? next(null) : null; 61 | logger("select collection " + collection.collectionName), makeDir(name + collection.collectionName + path.sep, function(err, name) { 62 | if (err) return last === ++index ? next(err) : error(err); 63 | meta(collection, metadata, function() { 64 | collection.find(query).snapshot(!0).stream().once("end", function() { 65 | return last === ++index ? next(null) : null; 66 | }).on("data", function(doc) { 67 | parser(doc, name); 68 | }); 69 | }); 70 | }); 71 | }); 72 | }); 73 | } 74 | 75 | function allCollectionsScan(db, name, numCursors, metadata, parser, next) { 76 | return db.collections(function(err, collections) { 77 | if (err) return next(err); 78 | var last = ~~collections.length, index = 0; 79 | if (0 === last) return next(null); 80 | collections.forEach(function(collection) { 81 | if (!0 === systemRegex.test(collection.collectionName)) return last === ++index ? next(null) : null; 82 | logger("select collection scan " + collection.collectionName), makeDir(name + collection.collectionName + path.sep, function(err, name) { 83 | if (err) return last === ++index ? next(err) : error(err); 84 | meta(collection, metadata, function() { 85 | collection.parallelCollectionScan({ 86 | numCursors: numCursors 87 | }, function(err, cursors) { 88 | if (err) return last === ++index ? next(err) : error(err); 89 | var ii, cursorsDone; 90 | if (0 === (ii = cursorsDone = ~~cursors.length)) return last === ++index ? next(null) : null; 91 | for (var i = 0; i < ii; ++i) cursors[i].once("end", function() { 92 | if (0 == --cursorsDone) return last === ++index ? next(null) : null; 93 | }).on("data", function(doc) { 94 | parser(doc, name); 95 | }); 96 | }); 97 | }); 98 | }); 99 | }); 100 | }); 101 | } 102 | 103 | function someCollections(db, name, query, metadata, parser, next, collections) { 104 | var last = ~~collections.length, index = 0; 105 | if (0 === last) return next(null); 106 | collections.forEach(function(collection) { 107 | db.collection(collection, { 108 | strict: !0 109 | }, function(err, collection) { 110 | if (err) return last === ++index ? next(err) : error(err); 111 | logger("select collection " + collection.collectionName), makeDir(name + collection.collectionName + path.sep, function(err, name) { 112 | if (err) return last === ++index ? next(err) : error(err); 113 | meta(collection, metadata, function() { 114 | collection.find(query).snapshot(!0).stream().once("end", function() { 115 | return last === ++index ? next(null) : null; 116 | }).on("data", function(doc) { 117 | parser(doc, name); 118 | }); 119 | }); 120 | }); 121 | }); 122 | }); 123 | } 124 | 125 | function someCollectionsScan(db, name, numCursors, metadata, parser, next, collections) { 126 | var last = ~~collections.length, index = 0; 127 | if (0 === last) return next(null); 128 | collections.forEach(function(collection) { 129 | db.collection(collection, { 130 | strict: !0 131 | }, function(err, collection) { 132 | if (err) return last === ++index ? next(err) : error(err); 133 | logger("select collection scan " + collection.collectionName), makeDir(name + collection.collectionName + path.sep, function(err, name) { 134 | if (err) return last === ++index ? next(err) : error(err); 135 | meta(collection, metadata, function() { 136 | collection.parallelCollectionScan({ 137 | numCursors: numCursors 138 | }, function(err, cursors) { 139 | if (err) return last === ++index ? next(err) : error(err); 140 | var ii, cursorsDone; 141 | if (0 === (ii = cursorsDone = ~~cursors.length)) return last === ++index ? next(null) : null; 142 | for (var i = 0; i < ii; ++i) cursors[i].once("end", function() { 143 | if (0 == --cursorsDone) return last === ++index ? next(null) : null; 144 | }).on("data", function(doc) { 145 | parser(doc, name); 146 | }); 147 | }); 148 | }); 149 | }); 150 | }); 151 | }); 152 | } 153 | 154 | function wrapper(my) { 155 | var parser; 156 | if ("function" == typeof my.parser) parser = my.parser; else switch (my.parser.toLowerCase()) { 157 | case "bson": 158 | BSON = new (BSON = require("bson"))(), parser = toBsonAsync; 159 | break; 160 | 161 | case "json": 162 | parser = toJsonAsync; 163 | break; 164 | 165 | default: 166 | throw new Error("missing parser option"); 167 | } 168 | var discriminator = allCollections; 169 | if (null !== my.collections ? (discriminator = someCollections, my.numCursors && (discriminator = someCollectionsScan, 170 | my.query = my.numCursors)) : my.numCursors && (discriminator = allCollectionsScan, 171 | my.query = my.numCursors), null === my.logger) logger = function() {}; else { 172 | (logger = require("logger-request")({ 173 | filename: my.logger, 174 | standalone: !0, 175 | daily: !0, 176 | winston: { 177 | logger: "_mongo_b" + my.logger, 178 | level: "info", 179 | json: !1 180 | } 181 | }))("backup start"); 182 | var log = require("mongodb").Logger; 183 | log.setLevel("info"), log.setCurrentLogger(function(msg) { 184 | return logger(msg); 185 | }); 186 | } 187 | var metadata = ""; 188 | function callback(err) { 189 | logger("backup stop"), null !== my.callback ? (logger("callback run"), my.callback(err)) : err && logger(err); 190 | } 191 | meta = !0 === my.metadata ? writeMetadata : function(a, b, c) { 192 | return c(); 193 | }, require("mongodb").MongoClient.connect(my.uri, my.options, function(err, db) { 194 | if (logger("db open"), err) return callback(err); 195 | var root = null === my.tar ? my.root : my.dir; 196 | makeDir(root, function(err, name) { 197 | if (err) return callback(err); 198 | makeDir(name + db.databaseName + path.sep, function(err, name) { 199 | function go() { 200 | return discriminator(db, name, my.query, metadata, parser, function(err) { 201 | if (logger("db close"), db.close(), err) return callback(err); 202 | my.tar ? makeDir(my.root, function(e, name) { 203 | var dest; 204 | err && error(err), my.stream ? (logger("send tar file to stream"), dest = my.stream) : (logger("make tar file at " + name + my.tar), 205 | dest = fs.createWriteStream(name + my.tar)); 206 | var packer = require("tar").Pack().on("error", callback).on("end", function() { 207 | rmDir(root), callback(null); 208 | }); 209 | require("fstream").Reader({ 210 | path: root + db.databaseName, 211 | type: "Directory" 212 | }).on("error", callback).pipe(packer).pipe(dest); 213 | }) : callback(null); 214 | }, my.collections); 215 | } 216 | if (err) return callback(err); 217 | !1 === my.metadata ? go() : makeDir(metadata = name + ".metadata" + path.sep, go); 218 | }); 219 | }); 220 | }); 221 | } 222 | 223 | function backup(options) { 224 | var opt = options || Object.create(null); 225 | if (!opt.uri) throw new Error("missing uri option"); 226 | if (!opt.stream) { 227 | if (!opt.root) throw new Error("missing root option"); 228 | if (fs.existsSync(opt.root) && !fs.statSync(opt.root).isDirectory()) throw new Error("root option is not a directory"); 229 | } 230 | var my = { 231 | dir: path.join(__dirname, "dump", path.sep), 232 | uri: String(opt.uri), 233 | root: path.resolve(String(opt.root || "")) + path.sep, 234 | stream: opt.stream || null, 235 | parser: opt.parser || "bson", 236 | numCursors: ~~opt.numCursors, 237 | collections: Array.isArray(opt.collections) ? opt.collections : null, 238 | callback: "function" == typeof opt.callback ? opt.callback : null, 239 | tar: "string" == typeof opt.tar ? opt.tar : null, 240 | query: "object" == typeof opt.query ? opt.query : {}, 241 | logger: "string" == typeof opt.logger ? path.resolve(opt.logger) : null, 242 | options: "object" == typeof opt.options ? opt.options : {}, 243 | metadata: Boolean(opt.metadata) 244 | }; 245 | return my.stream && (my.tar = !0), wrapper(my); 246 | } 247 | 248 | module.exports = backup; 249 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-backup", 3 | "version": "1.6.9", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "abbrev": { 8 | "version": "1.1.1", 9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 10 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 11 | "dev": true 12 | }, 13 | "align-text": { 14 | "version": "0.1.4", 15 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 16 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 17 | "dev": true, 18 | "requires": { 19 | "kind-of": "3.2.2", 20 | "longest": "1.0.1", 21 | "repeat-string": "1.6.1" 22 | } 23 | }, 24 | "amdefine": { 25 | "version": "1.0.1", 26 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 27 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 28 | "dev": true 29 | }, 30 | "ansi-regex": { 31 | "version": "2.1.1", 32 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 33 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 34 | "dev": true 35 | }, 36 | "ansi-styles": { 37 | "version": "2.2.1", 38 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 39 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 40 | "dev": true 41 | }, 42 | "argparse": { 43 | "version": "1.0.9", 44 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 45 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 46 | "dev": true, 47 | "requires": { 48 | "sprintf-js": "1.0.3" 49 | } 50 | }, 51 | "array-find-index": { 52 | "version": "1.0.2", 53 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 54 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", 55 | "dev": true 56 | }, 57 | "async": { 58 | "version": "1.0.0", 59 | "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", 60 | "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" 61 | }, 62 | "asynckit": { 63 | "version": "0.4.0", 64 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 65 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 66 | "dev": true 67 | }, 68 | "balanced-match": { 69 | "version": "1.0.0", 70 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 71 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 72 | }, 73 | "basic-authentication": { 74 | "version": "1.9.0", 75 | "resolved": "https://registry.npmjs.org/basic-authentication/-/basic-authentication-1.9.0.tgz", 76 | "integrity": "sha1-nMIYHaso20rMM2LKsYAzroYDObA=", 77 | "requires": { 78 | "setheaders": "0.3.0" 79 | } 80 | }, 81 | "block-stream": { 82 | "version": "0.0.9", 83 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", 84 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", 85 | "requires": { 86 | "inherits": "2.0.3" 87 | } 88 | }, 89 | "brace-expansion": { 90 | "version": "1.1.8", 91 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 92 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 93 | "requires": { 94 | "balanced-match": "1.0.0", 95 | "concat-map": "0.0.1" 96 | } 97 | }, 98 | "browser-stdout": { 99 | "version": "1.3.0", 100 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 101 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 102 | "dev": true 103 | }, 104 | "browserify-zlib": { 105 | "version": "0.1.4", 106 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", 107 | "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", 108 | "dev": true, 109 | "requires": { 110 | "pako": "0.2.9" 111 | } 112 | }, 113 | "bson": { 114 | "version": "1.0.4", 115 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz", 116 | "integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw=" 117 | }, 118 | "buffer-shims": { 119 | "version": "1.0.0", 120 | "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", 121 | "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" 122 | }, 123 | "builtin-modules": { 124 | "version": "1.1.1", 125 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 126 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 127 | "dev": true 128 | }, 129 | "camelcase": { 130 | "version": "2.1.1", 131 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 132 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", 133 | "dev": true 134 | }, 135 | "camelcase-keys": { 136 | "version": "2.1.0", 137 | "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", 138 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", 139 | "dev": true, 140 | "requires": { 141 | "camelcase": "2.1.1", 142 | "map-obj": "1.0.1" 143 | } 144 | }, 145 | "center-align": { 146 | "version": "0.1.3", 147 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 148 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 149 | "dev": true, 150 | "optional": true, 151 | "requires": { 152 | "align-text": "0.1.4", 153 | "lazy-cache": "1.0.4" 154 | } 155 | }, 156 | "chalk": { 157 | "version": "1.1.3", 158 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 159 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 160 | "dev": true, 161 | "requires": { 162 | "ansi-styles": "2.2.1", 163 | "escape-string-regexp": "1.0.5", 164 | "has-ansi": "2.0.0", 165 | "strip-ansi": "3.0.1", 166 | "supports-color": "2.0.0" 167 | } 168 | }, 169 | "cli": { 170 | "version": "1.0.1", 171 | "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", 172 | "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", 173 | "dev": true, 174 | "requires": { 175 | "exit": "0.1.2", 176 | "glob": "7.1.2" 177 | } 178 | }, 179 | "cliui": { 180 | "version": "2.1.0", 181 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 182 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 183 | "dev": true, 184 | "optional": true, 185 | "requires": { 186 | "center-align": "0.1.3", 187 | "right-align": "0.1.3", 188 | "wordwrap": "0.0.2" 189 | }, 190 | "dependencies": { 191 | "wordwrap": { 192 | "version": "0.0.2", 193 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 194 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", 195 | "dev": true, 196 | "optional": true 197 | } 198 | } 199 | }, 200 | "coffee-script": { 201 | "version": "1.10.0", 202 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", 203 | "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", 204 | "dev": true 205 | }, 206 | "colors": { 207 | "version": "1.0.3", 208 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", 209 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" 210 | }, 211 | "combined-stream": { 212 | "version": "1.0.5", 213 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 214 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 215 | "dev": true, 216 | "requires": { 217 | "delayed-stream": "1.0.0" 218 | } 219 | }, 220 | "commander": { 221 | "version": "2.13.0", 222 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", 223 | "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", 224 | "dev": true 225 | }, 226 | "component-emitter": { 227 | "version": "1.2.1", 228 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 229 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", 230 | "dev": true 231 | }, 232 | "concat-map": { 233 | "version": "0.0.1", 234 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 235 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 236 | }, 237 | "concat-stream": { 238 | "version": "1.6.0", 239 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", 240 | "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", 241 | "dev": true, 242 | "requires": { 243 | "inherits": "2.0.3", 244 | "readable-stream": "2.2.7", 245 | "typedarray": "0.0.6" 246 | } 247 | }, 248 | "console-browserify": { 249 | "version": "1.1.0", 250 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", 251 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", 252 | "dev": true, 253 | "requires": { 254 | "date-now": "0.1.4" 255 | } 256 | }, 257 | "cookiejar": { 258 | "version": "2.1.1", 259 | "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", 260 | "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=", 261 | "dev": true 262 | }, 263 | "core-util-is": { 264 | "version": "1.0.2", 265 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 266 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 267 | }, 268 | "currently-unhandled": { 269 | "version": "0.4.1", 270 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 271 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", 272 | "dev": true, 273 | "requires": { 274 | "array-find-index": "1.0.2" 275 | } 276 | }, 277 | "cycle": { 278 | "version": "1.0.3", 279 | "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", 280 | "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" 281 | }, 282 | "date-now": { 283 | "version": "0.1.4", 284 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", 285 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", 286 | "dev": true 287 | }, 288 | "dateformat": { 289 | "version": "1.0.12", 290 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", 291 | "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", 292 | "dev": true, 293 | "requires": { 294 | "get-stdin": "4.0.1", 295 | "meow": "3.7.0" 296 | } 297 | }, 298 | "debug": { 299 | "version": "3.1.0", 300 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 301 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 302 | "dev": true, 303 | "requires": { 304 | "ms": "2.0.0" 305 | } 306 | }, 307 | "decamelize": { 308 | "version": "1.2.0", 309 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 310 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 311 | "dev": true 312 | }, 313 | "deep-is": { 314 | "version": "0.1.3", 315 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 316 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 317 | "dev": true 318 | }, 319 | "delayed-stream": { 320 | "version": "1.0.0", 321 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 322 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 323 | "dev": true 324 | }, 325 | "diff": { 326 | "version": "3.3.1", 327 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", 328 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", 329 | "dev": true 330 | }, 331 | "dom-serializer": { 332 | "version": "0.1.0", 333 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", 334 | "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", 335 | "dev": true, 336 | "requires": { 337 | "domelementtype": "1.1.3", 338 | "entities": "1.1.1" 339 | }, 340 | "dependencies": { 341 | "domelementtype": { 342 | "version": "1.1.3", 343 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 344 | "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", 345 | "dev": true 346 | }, 347 | "entities": { 348 | "version": "1.1.1", 349 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", 350 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", 351 | "dev": true 352 | } 353 | } 354 | }, 355 | "domelementtype": { 356 | "version": "1.3.0", 357 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", 358 | "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", 359 | "dev": true 360 | }, 361 | "domhandler": { 362 | "version": "2.3.0", 363 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", 364 | "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", 365 | "dev": true, 366 | "requires": { 367 | "domelementtype": "1.3.0" 368 | } 369 | }, 370 | "domutils": { 371 | "version": "1.5.1", 372 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", 373 | "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", 374 | "dev": true, 375 | "requires": { 376 | "dom-serializer": "0.1.0", 377 | "domelementtype": "1.3.0" 378 | } 379 | }, 380 | "ee-first": { 381 | "version": "1.1.1", 382 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 383 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 384 | }, 385 | "entities": { 386 | "version": "1.0.0", 387 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", 388 | "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", 389 | "dev": true 390 | }, 391 | "error-ex": { 392 | "version": "1.3.1", 393 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", 394 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", 395 | "dev": true, 396 | "requires": { 397 | "is-arrayish": "0.2.1" 398 | } 399 | }, 400 | "es6-promise": { 401 | "version": "3.2.1", 402 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", 403 | "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" 404 | }, 405 | "escape-string-regexp": { 406 | "version": "1.0.5", 407 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 408 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 409 | "dev": true 410 | }, 411 | "escodegen": { 412 | "version": "1.8.1", 413 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", 414 | "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", 415 | "dev": true, 416 | "requires": { 417 | "esprima": "2.7.3", 418 | "estraverse": "1.9.3", 419 | "esutils": "2.0.2", 420 | "optionator": "0.8.2", 421 | "source-map": "0.2.0" 422 | }, 423 | "dependencies": { 424 | "source-map": { 425 | "version": "0.2.0", 426 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", 427 | "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", 428 | "dev": true, 429 | "optional": true, 430 | "requires": { 431 | "amdefine": "1.0.1" 432 | } 433 | } 434 | } 435 | }, 436 | "esprima": { 437 | "version": "2.7.3", 438 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 439 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 440 | "dev": true 441 | }, 442 | "estraverse": { 443 | "version": "1.9.3", 444 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", 445 | "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", 446 | "dev": true 447 | }, 448 | "esutils": { 449 | "version": "2.0.2", 450 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 451 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 452 | "dev": true 453 | }, 454 | "eventemitter2": { 455 | "version": "0.4.14", 456 | "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", 457 | "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", 458 | "dev": true 459 | }, 460 | "exit": { 461 | "version": "0.1.2", 462 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 463 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", 464 | "dev": true 465 | }, 466 | "extend": { 467 | "version": "3.0.1", 468 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 469 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", 470 | "dev": true 471 | }, 472 | "eyes": { 473 | "version": "0.1.8", 474 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 475 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" 476 | }, 477 | "fast-levenshtein": { 478 | "version": "2.0.6", 479 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 480 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 481 | "dev": true 482 | }, 483 | "figures": { 484 | "version": "1.7.0", 485 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", 486 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", 487 | "dev": true, 488 | "requires": { 489 | "escape-string-regexp": "1.0.5", 490 | "object-assign": "4.1.1" 491 | } 492 | }, 493 | "find-up": { 494 | "version": "1.1.2", 495 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 496 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 497 | "dev": true, 498 | "requires": { 499 | "path-exists": "2.1.0", 500 | "pinkie-promise": "2.0.1" 501 | } 502 | }, 503 | "findup-sync": { 504 | "version": "0.3.0", 505 | "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", 506 | "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", 507 | "dev": true, 508 | "requires": { 509 | "glob": "5.0.15" 510 | }, 511 | "dependencies": { 512 | "glob": { 513 | "version": "5.0.15", 514 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", 515 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 516 | "dev": true, 517 | "requires": { 518 | "inflight": "1.0.6", 519 | "inherits": "2.0.3", 520 | "minimatch": "3.0.4", 521 | "once": "1.4.0", 522 | "path-is-absolute": "1.0.1" 523 | } 524 | } 525 | } 526 | }, 527 | "form-data": { 528 | "version": "2.3.1", 529 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", 530 | "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", 531 | "dev": true, 532 | "requires": { 533 | "asynckit": "0.4.0", 534 | "combined-stream": "1.0.5", 535 | "mime-types": "2.1.17" 536 | } 537 | }, 538 | "formidable": { 539 | "version": "1.1.1", 540 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", 541 | "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", 542 | "dev": true 543 | }, 544 | "fs.realpath": { 545 | "version": "1.0.0", 546 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 547 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 548 | }, 549 | "fstream": { 550 | "version": "1.0.11", 551 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", 552 | "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", 553 | "requires": { 554 | "graceful-fs": "4.1.11", 555 | "inherits": "2.0.3", 556 | "mkdirp": "0.5.1", 557 | "rimraf": "2.6.2" 558 | } 559 | }, 560 | "get-stdin": { 561 | "version": "4.0.1", 562 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", 563 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", 564 | "dev": true 565 | }, 566 | "getobject": { 567 | "version": "0.1.0", 568 | "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", 569 | "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", 570 | "dev": true 571 | }, 572 | "glob": { 573 | "version": "7.1.2", 574 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 575 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 576 | "requires": { 577 | "fs.realpath": "1.0.0", 578 | "inflight": "1.0.6", 579 | "inherits": "2.0.3", 580 | "minimatch": "3.0.4", 581 | "once": "1.4.0", 582 | "path-is-absolute": "1.0.1" 583 | } 584 | }, 585 | "graceful-fs": { 586 | "version": "4.1.11", 587 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 588 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 589 | }, 590 | "growl": { 591 | "version": "1.10.3", 592 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", 593 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", 594 | "dev": true 595 | }, 596 | "grunt": { 597 | "version": "1.0.1", 598 | "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", 599 | "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", 600 | "dev": true, 601 | "requires": { 602 | "coffee-script": "1.10.0", 603 | "dateformat": "1.0.12", 604 | "eventemitter2": "0.4.14", 605 | "exit": "0.1.2", 606 | "findup-sync": "0.3.0", 607 | "glob": "7.0.6", 608 | "grunt-cli": "1.2.0", 609 | "grunt-known-options": "1.1.0", 610 | "grunt-legacy-log": "1.0.0", 611 | "grunt-legacy-util": "1.0.0", 612 | "iconv-lite": "0.4.19", 613 | "js-yaml": "3.5.5", 614 | "minimatch": "3.0.4", 615 | "nopt": "3.0.6", 616 | "path-is-absolute": "1.0.1", 617 | "rimraf": "2.2.8" 618 | }, 619 | "dependencies": { 620 | "glob": { 621 | "version": "7.0.6", 622 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", 623 | "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", 624 | "dev": true, 625 | "requires": { 626 | "fs.realpath": "1.0.0", 627 | "inflight": "1.0.6", 628 | "inherits": "2.0.3", 629 | "minimatch": "3.0.4", 630 | "once": "1.4.0", 631 | "path-is-absolute": "1.0.1" 632 | } 633 | }, 634 | "grunt-cli": { 635 | "version": "1.2.0", 636 | "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", 637 | "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", 638 | "dev": true, 639 | "requires": { 640 | "findup-sync": "0.3.0", 641 | "grunt-known-options": "1.1.0", 642 | "nopt": "3.0.6", 643 | "resolve": "1.1.7" 644 | } 645 | }, 646 | "rimraf": { 647 | "version": "2.2.8", 648 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", 649 | "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", 650 | "dev": true 651 | } 652 | } 653 | }, 654 | "grunt-contrib-jshint": { 655 | "version": "1.1.0", 656 | "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", 657 | "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", 658 | "dev": true, 659 | "requires": { 660 | "chalk": "1.1.3", 661 | "hooker": "0.2.3", 662 | "jshint": "2.9.5" 663 | } 664 | }, 665 | "grunt-contrib-uglify": { 666 | "version": "3.3.0", 667 | "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-3.3.0.tgz", 668 | "integrity": "sha512-W9O7lJE3PlD8VCc5fyaf98QV7f5wEDiU4PBIh0+/6UBbk2LhgzEFS0/p+taH5UD3+PlEn7QPN0o06Z0To6SqXw==", 669 | "dev": true, 670 | "requires": { 671 | "chalk": "1.1.3", 672 | "maxmin": "1.1.0", 673 | "uglify-js": "3.3.9", 674 | "uri-path": "1.0.0" 675 | } 676 | }, 677 | "grunt-endline": { 678 | "version": "0.7.0", 679 | "resolved": "https://registry.npmjs.org/grunt-endline/-/grunt-endline-0.7.0.tgz", 680 | "integrity": "sha512-NP2ABzCRBpuNfKgteVSEOR26zsph0oEFPVvEmSldkvxBHeSpUPOpIVxvrDnRHyKoV9hBuszGvVjHovjnG3aUBw==", 681 | "dev": true 682 | }, 683 | "grunt-known-options": { 684 | "version": "1.1.0", 685 | "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", 686 | "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=", 687 | "dev": true 688 | }, 689 | "grunt-legacy-log": { 690 | "version": "1.0.0", 691 | "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", 692 | "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", 693 | "dev": true, 694 | "requires": { 695 | "colors": "1.1.2", 696 | "grunt-legacy-log-utils": "1.0.0", 697 | "hooker": "0.2.3", 698 | "lodash": "3.10.1", 699 | "underscore.string": "3.2.3" 700 | }, 701 | "dependencies": { 702 | "colors": { 703 | "version": "1.1.2", 704 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", 705 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", 706 | "dev": true 707 | } 708 | } 709 | }, 710 | "grunt-legacy-log-utils": { 711 | "version": "1.0.0", 712 | "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", 713 | "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", 714 | "dev": true, 715 | "requires": { 716 | "chalk": "1.1.3", 717 | "lodash": "4.3.0" 718 | }, 719 | "dependencies": { 720 | "lodash": { 721 | "version": "4.3.0", 722 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", 723 | "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", 724 | "dev": true 725 | } 726 | } 727 | }, 728 | "grunt-legacy-util": { 729 | "version": "1.0.0", 730 | "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", 731 | "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", 732 | "dev": true, 733 | "requires": { 734 | "async": "1.5.2", 735 | "exit": "0.1.2", 736 | "getobject": "0.1.0", 737 | "hooker": "0.2.3", 738 | "lodash": "4.3.0", 739 | "underscore.string": "3.2.3", 740 | "which": "1.2.14" 741 | }, 742 | "dependencies": { 743 | "async": { 744 | "version": "1.5.2", 745 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 746 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 747 | "dev": true 748 | }, 749 | "lodash": { 750 | "version": "4.3.0", 751 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", 752 | "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", 753 | "dev": true 754 | } 755 | } 756 | }, 757 | "grunt-safer-regex": { 758 | "version": "0.1.0", 759 | "resolved": "https://registry.npmjs.org/grunt-safer-regex/-/grunt-safer-regex-0.1.0.tgz", 760 | "integrity": "sha512-kLLDEqliu6anbABm6lBZr8uAKP1fdrVzUzlYzQUOlrWrH/WpKlWeiowriM5fN0jXKViyPCh6S5oPA/C3Q91jzw==", 761 | "dev": true, 762 | "requires": { 763 | "safer-regex": "0.3.0" 764 | } 765 | }, 766 | "gzip-size": { 767 | "version": "1.0.0", 768 | "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", 769 | "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", 770 | "dev": true, 771 | "requires": { 772 | "browserify-zlib": "0.1.4", 773 | "concat-stream": "1.6.0" 774 | } 775 | }, 776 | "handlebars": { 777 | "version": "4.0.11", 778 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", 779 | "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", 780 | "dev": true, 781 | "requires": { 782 | "async": "1.5.2", 783 | "optimist": "0.6.1", 784 | "source-map": "0.4.4", 785 | "uglify-js": "2.8.29" 786 | }, 787 | "dependencies": { 788 | "async": { 789 | "version": "1.5.2", 790 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 791 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 792 | "dev": true 793 | }, 794 | "source-map": { 795 | "version": "0.4.4", 796 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 797 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 798 | "dev": true, 799 | "requires": { 800 | "amdefine": "1.0.1" 801 | } 802 | }, 803 | "uglify-js": { 804 | "version": "2.8.29", 805 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", 806 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", 807 | "dev": true, 808 | "optional": true, 809 | "requires": { 810 | "source-map": "0.5.7", 811 | "uglify-to-browserify": "1.0.2", 812 | "yargs": "3.10.0" 813 | }, 814 | "dependencies": { 815 | "source-map": { 816 | "version": "0.5.7", 817 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 818 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 819 | "dev": true, 820 | "optional": true 821 | } 822 | } 823 | } 824 | } 825 | }, 826 | "has-ansi": { 827 | "version": "2.0.0", 828 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 829 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 830 | "dev": true, 831 | "requires": { 832 | "ansi-regex": "2.1.1" 833 | } 834 | }, 835 | "has-flag": { 836 | "version": "1.0.0", 837 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 838 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 839 | "dev": true 840 | }, 841 | "he": { 842 | "version": "1.1.1", 843 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 844 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 845 | "dev": true 846 | }, 847 | "hooker": { 848 | "version": "0.2.3", 849 | "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", 850 | "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", 851 | "dev": true 852 | }, 853 | "hosted-git-info": { 854 | "version": "2.5.0", 855 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", 856 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", 857 | "dev": true 858 | }, 859 | "htmlparser2": { 860 | "version": "3.8.3", 861 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", 862 | "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", 863 | "dev": true, 864 | "requires": { 865 | "domelementtype": "1.3.0", 866 | "domhandler": "2.3.0", 867 | "domutils": "1.5.1", 868 | "entities": "1.0.0", 869 | "readable-stream": "1.1.14" 870 | }, 871 | "dependencies": { 872 | "isarray": { 873 | "version": "0.0.1", 874 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 875 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 876 | "dev": true 877 | }, 878 | "readable-stream": { 879 | "version": "1.1.14", 880 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 881 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 882 | "dev": true, 883 | "requires": { 884 | "core-util-is": "1.0.2", 885 | "inherits": "2.0.3", 886 | "isarray": "0.0.1", 887 | "string_decoder": "0.10.31" 888 | } 889 | }, 890 | "string_decoder": { 891 | "version": "0.10.31", 892 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 893 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 894 | "dev": true 895 | } 896 | } 897 | }, 898 | "iconv-lite": { 899 | "version": "0.4.19", 900 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 901 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", 902 | "dev": true 903 | }, 904 | "indent-string": { 905 | "version": "2.1.0", 906 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", 907 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", 908 | "dev": true, 909 | "requires": { 910 | "repeating": "2.0.1" 911 | } 912 | }, 913 | "inflight": { 914 | "version": "1.0.6", 915 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 916 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 917 | "requires": { 918 | "once": "1.4.0", 919 | "wrappy": "1.0.2" 920 | } 921 | }, 922 | "inherits": { 923 | "version": "2.0.3", 924 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 925 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 926 | }, 927 | "is-arrayish": { 928 | "version": "0.2.1", 929 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 930 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 931 | "dev": true 932 | }, 933 | "is-buffer": { 934 | "version": "1.1.6", 935 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 936 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 937 | "dev": true 938 | }, 939 | "is-builtin-module": { 940 | "version": "1.0.0", 941 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 942 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 943 | "dev": true, 944 | "requires": { 945 | "builtin-modules": "1.1.1" 946 | } 947 | }, 948 | "is-finite": { 949 | "version": "1.0.2", 950 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 951 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 952 | "dev": true, 953 | "requires": { 954 | "number-is-nan": "1.0.1" 955 | } 956 | }, 957 | "is-utf8": { 958 | "version": "0.2.1", 959 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 960 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 961 | "dev": true 962 | }, 963 | "isarray": { 964 | "version": "1.0.0", 965 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 966 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 967 | }, 968 | "isexe": { 969 | "version": "2.0.0", 970 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 971 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 972 | "dev": true 973 | }, 974 | "isstream": { 975 | "version": "0.1.2", 976 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 977 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 978 | }, 979 | "istanbul": { 980 | "version": "0.4.5", 981 | "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", 982 | "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", 983 | "dev": true, 984 | "requires": { 985 | "abbrev": "1.0.9", 986 | "async": "1.0.0", 987 | "escodegen": "1.8.1", 988 | "esprima": "2.7.3", 989 | "glob": "5.0.15", 990 | "handlebars": "4.0.11", 991 | "js-yaml": "3.5.5", 992 | "mkdirp": "0.5.1", 993 | "nopt": "3.0.6", 994 | "once": "1.4.0", 995 | "resolve": "1.1.7", 996 | "supports-color": "3.2.3", 997 | "which": "1.2.14", 998 | "wordwrap": "1.0.0" 999 | }, 1000 | "dependencies": { 1001 | "abbrev": { 1002 | "version": "1.0.9", 1003 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", 1004 | "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", 1005 | "dev": true 1006 | }, 1007 | "glob": { 1008 | "version": "5.0.15", 1009 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", 1010 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 1011 | "dev": true, 1012 | "requires": { 1013 | "inflight": "1.0.6", 1014 | "inherits": "2.0.3", 1015 | "minimatch": "3.0.4", 1016 | "once": "1.4.0", 1017 | "path-is-absolute": "1.0.1" 1018 | } 1019 | }, 1020 | "supports-color": { 1021 | "version": "3.2.3", 1022 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 1023 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 1024 | "dev": true, 1025 | "requires": { 1026 | "has-flag": "1.0.0" 1027 | } 1028 | } 1029 | } 1030 | }, 1031 | "js-yaml": { 1032 | "version": "3.5.5", 1033 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", 1034 | "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", 1035 | "dev": true, 1036 | "requires": { 1037 | "argparse": "1.0.9", 1038 | "esprima": "2.7.3" 1039 | } 1040 | }, 1041 | "jshint": { 1042 | "version": "2.9.5", 1043 | "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", 1044 | "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", 1045 | "dev": true, 1046 | "requires": { 1047 | "cli": "1.0.1", 1048 | "console-browserify": "1.1.0", 1049 | "exit": "0.1.2", 1050 | "htmlparser2": "3.8.3", 1051 | "lodash": "3.7.0", 1052 | "minimatch": "3.0.4", 1053 | "shelljs": "0.3.0", 1054 | "strip-json-comments": "1.0.4" 1055 | }, 1056 | "dependencies": { 1057 | "lodash": { 1058 | "version": "3.7.0", 1059 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", 1060 | "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", 1061 | "dev": true 1062 | } 1063 | } 1064 | }, 1065 | "kind-of": { 1066 | "version": "3.2.2", 1067 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1068 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1069 | "dev": true, 1070 | "requires": { 1071 | "is-buffer": "1.1.6" 1072 | } 1073 | }, 1074 | "lazy-cache": { 1075 | "version": "1.0.4", 1076 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 1077 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", 1078 | "dev": true, 1079 | "optional": true 1080 | }, 1081 | "levn": { 1082 | "version": "0.3.0", 1083 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1084 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1085 | "dev": true, 1086 | "requires": { 1087 | "prelude-ls": "1.1.2", 1088 | "type-check": "0.3.2" 1089 | } 1090 | }, 1091 | "load-json-file": { 1092 | "version": "1.1.0", 1093 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 1094 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 1095 | "dev": true, 1096 | "requires": { 1097 | "graceful-fs": "4.1.11", 1098 | "parse-json": "2.2.0", 1099 | "pify": "2.3.0", 1100 | "pinkie-promise": "2.0.1", 1101 | "strip-bom": "2.0.0" 1102 | } 1103 | }, 1104 | "lodash": { 1105 | "version": "3.10.1", 1106 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", 1107 | "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", 1108 | "dev": true 1109 | }, 1110 | "logger-request": { 1111 | "version": "3.8.0", 1112 | "resolved": "https://registry.npmjs.org/logger-request/-/logger-request-3.8.0.tgz", 1113 | "integrity": "sha1-A6symboJR2w5oTta8pdInam7Zyk=", 1114 | "requires": { 1115 | "basic-authentication": "1.9.0", 1116 | "on-finished": "2.3.0", 1117 | "transfer-rate": "2.1.0", 1118 | "winston": "2.3.1", 1119 | "winston-daily-rotate-file": "1.4.6" 1120 | } 1121 | }, 1122 | "longest": { 1123 | "version": "1.0.1", 1124 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 1125 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", 1126 | "dev": true 1127 | }, 1128 | "loud-rejection": { 1129 | "version": "1.6.0", 1130 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", 1131 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", 1132 | "dev": true, 1133 | "requires": { 1134 | "currently-unhandled": "0.4.1", 1135 | "signal-exit": "3.0.2" 1136 | } 1137 | }, 1138 | "map-obj": { 1139 | "version": "1.0.1", 1140 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", 1141 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", 1142 | "dev": true 1143 | }, 1144 | "maxmin": { 1145 | "version": "1.1.0", 1146 | "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", 1147 | "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", 1148 | "dev": true, 1149 | "requires": { 1150 | "chalk": "1.1.3", 1151 | "figures": "1.7.0", 1152 | "gzip-size": "1.0.0", 1153 | "pretty-bytes": "1.0.4" 1154 | } 1155 | }, 1156 | "meow": { 1157 | "version": "3.7.0", 1158 | "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", 1159 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", 1160 | "dev": true, 1161 | "requires": { 1162 | "camelcase-keys": "2.1.0", 1163 | "decamelize": "1.2.0", 1164 | "loud-rejection": "1.6.0", 1165 | "map-obj": "1.0.1", 1166 | "minimist": "1.2.0", 1167 | "normalize-package-data": "2.4.0", 1168 | "object-assign": "4.1.1", 1169 | "read-pkg-up": "1.0.1", 1170 | "redent": "1.0.0", 1171 | "trim-newlines": "1.0.0" 1172 | }, 1173 | "dependencies": { 1174 | "minimist": { 1175 | "version": "1.2.0", 1176 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1177 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 1178 | "dev": true 1179 | } 1180 | } 1181 | }, 1182 | "methods": { 1183 | "version": "1.1.2", 1184 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1185 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", 1186 | "dev": true 1187 | }, 1188 | "mime": { 1189 | "version": "1.6.0", 1190 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1191 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 1192 | "dev": true 1193 | }, 1194 | "mime-db": { 1195 | "version": "1.30.0", 1196 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 1197 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", 1198 | "dev": true 1199 | }, 1200 | "mime-types": { 1201 | "version": "2.1.17", 1202 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 1203 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 1204 | "dev": true, 1205 | "requires": { 1206 | "mime-db": "1.30.0" 1207 | } 1208 | }, 1209 | "minimatch": { 1210 | "version": "3.0.4", 1211 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1212 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1213 | "requires": { 1214 | "brace-expansion": "1.1.8" 1215 | } 1216 | }, 1217 | "minimist": { 1218 | "version": "0.0.8", 1219 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1220 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 1221 | }, 1222 | "mkdirp": { 1223 | "version": "0.5.1", 1224 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1225 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1226 | "requires": { 1227 | "minimist": "0.0.8" 1228 | } 1229 | }, 1230 | "mocha": { 1231 | "version": "4.1.0", 1232 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", 1233 | "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", 1234 | "dev": true, 1235 | "requires": { 1236 | "browser-stdout": "1.3.0", 1237 | "commander": "2.11.0", 1238 | "debug": "3.1.0", 1239 | "diff": "3.3.1", 1240 | "escape-string-regexp": "1.0.5", 1241 | "glob": "7.1.2", 1242 | "growl": "1.10.3", 1243 | "he": "1.1.1", 1244 | "mkdirp": "0.5.1", 1245 | "supports-color": "4.4.0" 1246 | }, 1247 | "dependencies": { 1248 | "commander": { 1249 | "version": "2.11.0", 1250 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 1251 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 1252 | "dev": true 1253 | }, 1254 | "has-flag": { 1255 | "version": "2.0.0", 1256 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 1257 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 1258 | "dev": true 1259 | }, 1260 | "supports-color": { 1261 | "version": "4.4.0", 1262 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", 1263 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", 1264 | "dev": true, 1265 | "requires": { 1266 | "has-flag": "2.0.0" 1267 | } 1268 | } 1269 | } 1270 | }, 1271 | "mongodb": { 1272 | "version": "2.2.31", 1273 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.31.tgz", 1274 | "integrity": "sha1-GUBEXGYeGSF7s7+CRdmFSq71SNs=", 1275 | "requires": { 1276 | "es6-promise": "3.2.1", 1277 | "mongodb-core": "2.1.15", 1278 | "readable-stream": "2.2.7" 1279 | } 1280 | }, 1281 | "mongodb-core": { 1282 | "version": "2.1.15", 1283 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.15.tgz", 1284 | "integrity": "sha1-hB9TuH//9MdFgYnDXIroJ+EWl2Q=", 1285 | "requires": { 1286 | "bson": "1.0.4", 1287 | "require_optional": "1.0.1" 1288 | } 1289 | }, 1290 | "mongodb-restore": { 1291 | "version": "1.6.2", 1292 | "resolved": "https://registry.npmjs.org/mongodb-restore/-/mongodb-restore-1.6.2.tgz", 1293 | "integrity": "sha1-iGMAf0+Esy0txVnleqdcRtwtlXg=", 1294 | "dev": true, 1295 | "requires": { 1296 | "bson": "1.0.1", 1297 | "graceful-fs": "4.1.11", 1298 | "logger-request": "3.7.3", 1299 | "mongodb": "2.2.16", 1300 | "tar": "2.2.1" 1301 | }, 1302 | "dependencies": { 1303 | "basic-authentication": { 1304 | "version": "1.7.0", 1305 | "resolved": "https://registry.npmjs.org/basic-authentication/-/basic-authentication-1.7.0.tgz", 1306 | "integrity": "sha1-odDu+3x257O8cNrxO0WF2+qZZbE=", 1307 | "dev": true, 1308 | "requires": { 1309 | "setheaders": "0.1.7" 1310 | } 1311 | }, 1312 | "bson": { 1313 | "version": "1.0.1", 1314 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.1.tgz", 1315 | "integrity": "sha1-OlrdsPL/iLw0NucI5L24Y3YC1y0=", 1316 | "dev": true 1317 | }, 1318 | "logger-request": { 1319 | "version": "3.7.3", 1320 | "resolved": "https://registry.npmjs.org/logger-request/-/logger-request-3.7.3.tgz", 1321 | "integrity": "sha1-sm8tGbn5msFvu/gXfg78h9rNmb0=", 1322 | "dev": true, 1323 | "requires": { 1324 | "basic-authentication": "1.7.0", 1325 | "on-finished": "2.3.0", 1326 | "transfer-rate": "1.2.0", 1327 | "winston": "2.3.0", 1328 | "winston-daily-rotate-file": "1.4.0" 1329 | } 1330 | }, 1331 | "mongodb": { 1332 | "version": "2.2.16", 1333 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.16.tgz", 1334 | "integrity": "sha1-4yupHPninzcfs4ugxKccOx9frnc=", 1335 | "dev": true, 1336 | "requires": { 1337 | "es6-promise": "3.2.1", 1338 | "mongodb-core": "2.1.2", 1339 | "readable-stream": "2.1.5" 1340 | } 1341 | }, 1342 | "mongodb-core": { 1343 | "version": "2.1.2", 1344 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.2.tgz", 1345 | "integrity": "sha1-oR23c9NIGcvrl3USQYJxN6tTWqs=", 1346 | "dev": true, 1347 | "requires": { 1348 | "bson": "1.0.1", 1349 | "require_optional": "1.0.1" 1350 | } 1351 | }, 1352 | "readable-stream": { 1353 | "version": "2.1.5", 1354 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", 1355 | "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", 1356 | "dev": true, 1357 | "requires": { 1358 | "buffer-shims": "1.0.0", 1359 | "core-util-is": "1.0.2", 1360 | "inherits": "2.0.3", 1361 | "isarray": "1.0.0", 1362 | "process-nextick-args": "1.0.7", 1363 | "string_decoder": "0.10.31", 1364 | "util-deprecate": "1.0.2" 1365 | } 1366 | }, 1367 | "setheaders": { 1368 | "version": "0.1.7", 1369 | "resolved": "https://registry.npmjs.org/setheaders/-/setheaders-0.1.7.tgz", 1370 | "integrity": "sha1-1nsGRDax+UbXpVeNpt8qOdL3LP0=", 1371 | "dev": true 1372 | }, 1373 | "string_decoder": { 1374 | "version": "0.10.31", 1375 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1376 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 1377 | "dev": true 1378 | }, 1379 | "transfer-rate": { 1380 | "version": "1.2.0", 1381 | "resolved": "https://registry.npmjs.org/transfer-rate/-/transfer-rate-1.2.0.tgz", 1382 | "integrity": "sha1-QoAJTeXCJmaMcS8pg+A7CAw7pJk=", 1383 | "dev": true 1384 | }, 1385 | "winston": { 1386 | "version": "2.3.0", 1387 | "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.0.tgz", 1388 | "integrity": "sha1-IH+qq2/M8/5JN0PdKwPbr8fOt4w=", 1389 | "dev": true, 1390 | "requires": { 1391 | "async": "1.0.0", 1392 | "colors": "1.0.3", 1393 | "cycle": "1.0.3", 1394 | "eyes": "0.1.8", 1395 | "isstream": "0.1.2", 1396 | "stack-trace": "0.0.10" 1397 | } 1398 | }, 1399 | "winston-daily-rotate-file": { 1400 | "version": "1.4.0", 1401 | "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-1.4.0.tgz", 1402 | "integrity": "sha1-cQUvTDcrp8WuFjg0xbBD7dDAa+A=", 1403 | "dev": true 1404 | } 1405 | } 1406 | }, 1407 | "ms": { 1408 | "version": "2.0.0", 1409 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1410 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1411 | "dev": true 1412 | }, 1413 | "nopt": { 1414 | "version": "3.0.6", 1415 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 1416 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 1417 | "dev": true, 1418 | "requires": { 1419 | "abbrev": "1.1.1" 1420 | } 1421 | }, 1422 | "normalize-package-data": { 1423 | "version": "2.4.0", 1424 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1425 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1426 | "dev": true, 1427 | "requires": { 1428 | "hosted-git-info": "2.5.0", 1429 | "is-builtin-module": "1.0.0", 1430 | "semver": "5.5.0", 1431 | "validate-npm-package-license": "3.0.1" 1432 | } 1433 | }, 1434 | "number-is-nan": { 1435 | "version": "1.0.1", 1436 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1437 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1438 | "dev": true 1439 | }, 1440 | "object-assign": { 1441 | "version": "4.1.1", 1442 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1443 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1444 | "dev": true 1445 | }, 1446 | "on-finished": { 1447 | "version": "2.3.0", 1448 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1449 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1450 | "requires": { 1451 | "ee-first": "1.1.1" 1452 | } 1453 | }, 1454 | "once": { 1455 | "version": "1.4.0", 1456 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1457 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1458 | "requires": { 1459 | "wrappy": "1.0.2" 1460 | } 1461 | }, 1462 | "optimist": { 1463 | "version": "0.6.1", 1464 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 1465 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 1466 | "dev": true, 1467 | "requires": { 1468 | "minimist": "0.0.8", 1469 | "wordwrap": "0.0.3" 1470 | }, 1471 | "dependencies": { 1472 | "wordwrap": { 1473 | "version": "0.0.3", 1474 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 1475 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 1476 | "dev": true 1477 | } 1478 | } 1479 | }, 1480 | "optionator": { 1481 | "version": "0.8.2", 1482 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1483 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1484 | "dev": true, 1485 | "requires": { 1486 | "deep-is": "0.1.3", 1487 | "fast-levenshtein": "2.0.6", 1488 | "levn": "0.3.0", 1489 | "prelude-ls": "1.1.2", 1490 | "type-check": "0.3.2", 1491 | "wordwrap": "1.0.0" 1492 | } 1493 | }, 1494 | "pako": { 1495 | "version": "0.2.9", 1496 | "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", 1497 | "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", 1498 | "dev": true 1499 | }, 1500 | "parse-json": { 1501 | "version": "2.2.0", 1502 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1503 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1504 | "dev": true, 1505 | "requires": { 1506 | "error-ex": "1.3.1" 1507 | } 1508 | }, 1509 | "path-exists": { 1510 | "version": "2.1.0", 1511 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1512 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1513 | "dev": true, 1514 | "requires": { 1515 | "pinkie-promise": "2.0.1" 1516 | } 1517 | }, 1518 | "path-is-absolute": { 1519 | "version": "1.0.1", 1520 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1521 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1522 | }, 1523 | "path-type": { 1524 | "version": "1.1.0", 1525 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 1526 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 1527 | "dev": true, 1528 | "requires": { 1529 | "graceful-fs": "4.1.11", 1530 | "pify": "2.3.0", 1531 | "pinkie-promise": "2.0.1" 1532 | } 1533 | }, 1534 | "pify": { 1535 | "version": "2.3.0", 1536 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1537 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1538 | "dev": true 1539 | }, 1540 | "pinkie": { 1541 | "version": "2.0.4", 1542 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1543 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1544 | "dev": true 1545 | }, 1546 | "pinkie-promise": { 1547 | "version": "2.0.1", 1548 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1549 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1550 | "dev": true, 1551 | "requires": { 1552 | "pinkie": "2.0.4" 1553 | } 1554 | }, 1555 | "prelude-ls": { 1556 | "version": "1.1.2", 1557 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1558 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1559 | "dev": true 1560 | }, 1561 | "pretty-bytes": { 1562 | "version": "1.0.4", 1563 | "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", 1564 | "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", 1565 | "dev": true, 1566 | "requires": { 1567 | "get-stdin": "4.0.1", 1568 | "meow": "3.7.0" 1569 | } 1570 | }, 1571 | "process-nextick-args": { 1572 | "version": "1.0.7", 1573 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 1574 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 1575 | }, 1576 | "qs": { 1577 | "version": "6.5.1", 1578 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 1579 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", 1580 | "dev": true 1581 | }, 1582 | "read-pkg": { 1583 | "version": "1.1.0", 1584 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 1585 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 1586 | "dev": true, 1587 | "requires": { 1588 | "load-json-file": "1.1.0", 1589 | "normalize-package-data": "2.4.0", 1590 | "path-type": "1.1.0" 1591 | } 1592 | }, 1593 | "read-pkg-up": { 1594 | "version": "1.0.1", 1595 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 1596 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 1597 | "dev": true, 1598 | "requires": { 1599 | "find-up": "1.1.2", 1600 | "read-pkg": "1.1.0" 1601 | } 1602 | }, 1603 | "readable-stream": { 1604 | "version": "2.2.7", 1605 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", 1606 | "integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=", 1607 | "requires": { 1608 | "buffer-shims": "1.0.0", 1609 | "core-util-is": "1.0.2", 1610 | "inherits": "2.0.3", 1611 | "isarray": "1.0.0", 1612 | "process-nextick-args": "1.0.7", 1613 | "string_decoder": "1.0.3", 1614 | "util-deprecate": "1.0.2" 1615 | } 1616 | }, 1617 | "redent": { 1618 | "version": "1.0.0", 1619 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", 1620 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", 1621 | "dev": true, 1622 | "requires": { 1623 | "indent-string": "2.1.0", 1624 | "strip-indent": "1.0.1" 1625 | } 1626 | }, 1627 | "repeat-string": { 1628 | "version": "1.6.1", 1629 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1630 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 1631 | "dev": true 1632 | }, 1633 | "repeating": { 1634 | "version": "2.0.1", 1635 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 1636 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 1637 | "dev": true, 1638 | "requires": { 1639 | "is-finite": "1.0.2" 1640 | } 1641 | }, 1642 | "require_optional": { 1643 | "version": "1.0.1", 1644 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", 1645 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", 1646 | "requires": { 1647 | "resolve-from": "2.0.0", 1648 | "semver": "5.5.0" 1649 | } 1650 | }, 1651 | "resolve": { 1652 | "version": "1.1.7", 1653 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 1654 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 1655 | "dev": true 1656 | }, 1657 | "resolve-from": { 1658 | "version": "2.0.0", 1659 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", 1660 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" 1661 | }, 1662 | "ret": { 1663 | "version": "0.1.15", 1664 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 1665 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", 1666 | "dev": true 1667 | }, 1668 | "right-align": { 1669 | "version": "0.1.3", 1670 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 1671 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 1672 | "dev": true, 1673 | "optional": true, 1674 | "requires": { 1675 | "align-text": "0.1.4" 1676 | } 1677 | }, 1678 | "rimraf": { 1679 | "version": "2.6.2", 1680 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 1681 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 1682 | "requires": { 1683 | "glob": "7.1.2" 1684 | } 1685 | }, 1686 | "safe-buffer": { 1687 | "version": "5.1.1", 1688 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1689 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 1690 | }, 1691 | "safe-regex": { 1692 | "version": "1.1.0", 1693 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 1694 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 1695 | "dev": true, 1696 | "requires": { 1697 | "ret": "0.1.15" 1698 | } 1699 | }, 1700 | "safer-regex": { 1701 | "version": "0.3.0", 1702 | "resolved": "https://registry.npmjs.org/safer-regex/-/safer-regex-0.3.0.tgz", 1703 | "integrity": "sha512-ioiqZFoe9VTR3irkY19QyAJ+6J6l/v1RkHIuZFXMY4IYB2sFwi2wU3XG6BupkAS8XsOWI1lKx11grsWwkCbgrg==", 1704 | "dev": true, 1705 | "requires": { 1706 | "cli": "1.0.1", 1707 | "safe-regex": "1.1.0" 1708 | } 1709 | }, 1710 | "semver": { 1711 | "version": "5.5.0", 1712 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 1713 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" 1714 | }, 1715 | "setheaders": { 1716 | "version": "0.3.0", 1717 | "resolved": "https://registry.npmjs.org/setheaders/-/setheaders-0.3.0.tgz", 1718 | "integrity": "sha1-PnSfM3ou58GGwuDdB/RftHJIjhM=" 1719 | }, 1720 | "shelljs": { 1721 | "version": "0.3.0", 1722 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", 1723 | "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", 1724 | "dev": true 1725 | }, 1726 | "signal-exit": { 1727 | "version": "3.0.2", 1728 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1729 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1730 | "dev": true 1731 | }, 1732 | "source-map": { 1733 | "version": "0.6.1", 1734 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1735 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1736 | "dev": true 1737 | }, 1738 | "spdx-correct": { 1739 | "version": "1.0.2", 1740 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", 1741 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", 1742 | "dev": true, 1743 | "requires": { 1744 | "spdx-license-ids": "1.2.2" 1745 | } 1746 | }, 1747 | "spdx-expression-parse": { 1748 | "version": "1.0.4", 1749 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", 1750 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", 1751 | "dev": true 1752 | }, 1753 | "spdx-license-ids": { 1754 | "version": "1.2.2", 1755 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", 1756 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", 1757 | "dev": true 1758 | }, 1759 | "sprintf-js": { 1760 | "version": "1.0.3", 1761 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1762 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1763 | "dev": true 1764 | }, 1765 | "stack-trace": { 1766 | "version": "0.0.10", 1767 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 1768 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" 1769 | }, 1770 | "string_decoder": { 1771 | "version": "1.0.3", 1772 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 1773 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 1774 | "requires": { 1775 | "safe-buffer": "5.1.1" 1776 | } 1777 | }, 1778 | "strip-ansi": { 1779 | "version": "3.0.1", 1780 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1781 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1782 | "dev": true, 1783 | "requires": { 1784 | "ansi-regex": "2.1.1" 1785 | } 1786 | }, 1787 | "strip-bom": { 1788 | "version": "2.0.0", 1789 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 1790 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 1791 | "dev": true, 1792 | "requires": { 1793 | "is-utf8": "0.2.1" 1794 | } 1795 | }, 1796 | "strip-indent": { 1797 | "version": "1.0.1", 1798 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", 1799 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", 1800 | "dev": true, 1801 | "requires": { 1802 | "get-stdin": "4.0.1" 1803 | } 1804 | }, 1805 | "strip-json-comments": { 1806 | "version": "1.0.4", 1807 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", 1808 | "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", 1809 | "dev": true 1810 | }, 1811 | "superagent": { 1812 | "version": "3.8.2", 1813 | "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz", 1814 | "integrity": "sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ==", 1815 | "dev": true, 1816 | "requires": { 1817 | "component-emitter": "1.2.1", 1818 | "cookiejar": "2.1.1", 1819 | "debug": "3.1.0", 1820 | "extend": "3.0.1", 1821 | "form-data": "2.3.1", 1822 | "formidable": "1.1.1", 1823 | "methods": "1.1.2", 1824 | "mime": "1.6.0", 1825 | "qs": "6.5.1", 1826 | "readable-stream": "2.2.7" 1827 | } 1828 | }, 1829 | "supertest": { 1830 | "version": "3.0.0", 1831 | "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz", 1832 | "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", 1833 | "dev": true, 1834 | "requires": { 1835 | "methods": "1.1.2", 1836 | "superagent": "3.8.2" 1837 | } 1838 | }, 1839 | "supports-color": { 1840 | "version": "2.0.0", 1841 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1842 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1843 | "dev": true 1844 | }, 1845 | "tar": { 1846 | "version": "2.2.1", 1847 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", 1848 | "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", 1849 | "requires": { 1850 | "block-stream": "0.0.9", 1851 | "fstream": "1.0.11", 1852 | "inherits": "2.0.3" 1853 | } 1854 | }, 1855 | "transfer-rate": { 1856 | "version": "2.1.0", 1857 | "resolved": "https://registry.npmjs.org/transfer-rate/-/transfer-rate-2.1.0.tgz", 1858 | "integrity": "sha1-4OZYV2rGUKT+H+qeFLQ49ScMo+Y=", 1859 | "requires": { 1860 | "on-finished": "2.3.0" 1861 | } 1862 | }, 1863 | "trim-newlines": { 1864 | "version": "1.0.0", 1865 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", 1866 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", 1867 | "dev": true 1868 | }, 1869 | "type-check": { 1870 | "version": "0.3.2", 1871 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1872 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1873 | "dev": true, 1874 | "requires": { 1875 | "prelude-ls": "1.1.2" 1876 | } 1877 | }, 1878 | "typedarray": { 1879 | "version": "0.0.6", 1880 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1881 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1882 | "dev": true 1883 | }, 1884 | "uglify-js": { 1885 | "version": "3.3.9", 1886 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.9.tgz", 1887 | "integrity": "sha512-J2t8B5tj9JdPTW4+sNZXmiIWHzTvcoITkaqzTiilu/biZF/9crqf/Fi7k5hqbOmVRh9/hVNxAxBYIMF7N6SqMQ==", 1888 | "dev": true, 1889 | "requires": { 1890 | "commander": "2.13.0", 1891 | "source-map": "0.6.1" 1892 | } 1893 | }, 1894 | "uglify-to-browserify": { 1895 | "version": "1.0.2", 1896 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 1897 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", 1898 | "dev": true, 1899 | "optional": true 1900 | }, 1901 | "underscore.string": { 1902 | "version": "3.2.3", 1903 | "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", 1904 | "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", 1905 | "dev": true 1906 | }, 1907 | "uri-path": { 1908 | "version": "1.0.0", 1909 | "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", 1910 | "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", 1911 | "dev": true 1912 | }, 1913 | "util-deprecate": { 1914 | "version": "1.0.2", 1915 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1916 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1917 | }, 1918 | "validate-npm-package-license": { 1919 | "version": "3.0.1", 1920 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", 1921 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", 1922 | "dev": true, 1923 | "requires": { 1924 | "spdx-correct": "1.0.2", 1925 | "spdx-expression-parse": "1.0.4" 1926 | } 1927 | }, 1928 | "which": { 1929 | "version": "1.2.14", 1930 | "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", 1931 | "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", 1932 | "dev": true, 1933 | "requires": { 1934 | "isexe": "2.0.0" 1935 | } 1936 | }, 1937 | "window-size": { 1938 | "version": "0.1.0", 1939 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 1940 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", 1941 | "dev": true, 1942 | "optional": true 1943 | }, 1944 | "winston": { 1945 | "version": "2.3.1", 1946 | "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", 1947 | "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", 1948 | "requires": { 1949 | "async": "1.0.0", 1950 | "colors": "1.0.3", 1951 | "cycle": "1.0.3", 1952 | "eyes": "0.1.8", 1953 | "isstream": "0.1.2", 1954 | "stack-trace": "0.0.10" 1955 | } 1956 | }, 1957 | "winston-daily-rotate-file": { 1958 | "version": "1.4.6", 1959 | "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-1.4.6.tgz", 1960 | "integrity": "sha1-8gS2raGaU4b99S/pl9jhDkP/d4g=" 1961 | }, 1962 | "wordwrap": { 1963 | "version": "1.0.0", 1964 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1965 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1966 | "dev": true 1967 | }, 1968 | "wrappy": { 1969 | "version": "1.0.2", 1970 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1971 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1972 | }, 1973 | "yargs": { 1974 | "version": "3.10.0", 1975 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 1976 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 1977 | "dev": true, 1978 | "optional": true, 1979 | "requires": { 1980 | "camelcase": "1.2.1", 1981 | "cliui": "2.1.0", 1982 | "decamelize": "1.2.0", 1983 | "window-size": "0.1.0" 1984 | }, 1985 | "dependencies": { 1986 | "camelcase": { 1987 | "version": "1.2.1", 1988 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 1989 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", 1990 | "dev": true, 1991 | "optional": true 1992 | } 1993 | } 1994 | } 1995 | } 1996 | } 1997 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.6.9", 3 | "name": "mongodb-backup", 4 | "description": "backup for mongodb", 5 | "keywords": [ 6 | "mongodb", 7 | "backup", 8 | "dump" 9 | ], 10 | "preferGlobal": false, 11 | "homepage": "https://github.com/hex7c0/mongodb-backup", 12 | "author": { 13 | "name": "hex7c0", 14 | "email": "hex7c0@gmail.com", 15 | "url": "https://hex7c0.github.io/" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/hex7c0/mongodb-backup.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/hex7c0/mongodb-backup/issues", 23 | "email": "hex7c0@gmail.com" 24 | }, 25 | "main": "index.min.js", 26 | "dependencies": { 27 | "bson": "1.0.4", 28 | "fstream": "1.0.11", 29 | "graceful-fs": "4.1.11", 30 | "logger-request": "3.8.0", 31 | "mongodb": "2.2.31", 32 | "tar": "2.2.1" 33 | }, 34 | "devDependencies": { 35 | "grunt": "~1.0", 36 | "grunt-contrib-uglify": "~3.3", 37 | "grunt-contrib-jshint": "~1.1", 38 | "grunt-endline": "~0.7", 39 | "grunt-safer-regex": "~0.1", 40 | "istanbul": "~0.4", 41 | "mocha": "~4.1", 42 | "mongodb-restore": "~1.6", 43 | "supertest": "~3.0" 44 | }, 45 | "engines": { 46 | "node": ">=4" 47 | }, 48 | "scripts": { 49 | "prepare": "npm prune", 50 | "prepublishOnly": "grunt", 51 | "test": "mocha --bail --check-leaks --globals Promise --timeout 10000", 52 | "test-cov": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --timeout 10000" 53 | }, 54 | "license": "Apache-2.0" 55 | } 56 | -------------------------------------------------------------------------------- /test/data.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file data test 4 | * @module mongodb-backup 5 | * @package mongodb-backup 6 | * @subpackage test 7 | * @version 0.0.1 8 | * @author hex7c0 9 | * @license GPLv3 10 | */ 11 | 12 | /* 13 | * initialize module 14 | */ 15 | var backup = require('..'); 16 | var assert = require('assert'); 17 | var fs = require('fs'); 18 | var extname = require('path').extname; 19 | var client = require('mongodb').MongoClient; 20 | var BSON = require('bson'); 21 | BSON = new BSON(); 22 | var URI = process.env.URI; 23 | 24 | /* 25 | * test module 26 | */ 27 | describe('data', function() { 28 | 29 | var DOCS = {}; 30 | var ROOT = __dirname + '/dump'; 31 | 32 | describe('db query', function() { 33 | 34 | it('should return data from "logins" collection', function(done) { 35 | 36 | client.connect(URI, function(err, db) { 37 | 38 | db.collection('logins', function(err, collection) { 39 | 40 | collection.find({}).toArray(function(err, docs) { 41 | 42 | assert.equal(docs.length > 0, true, 'not empty collection'); 43 | for (var i = 0, ii = docs.length; i < ii; i++) { 44 | DOCS[docs[i]._id] = docs[i]; 45 | } 46 | db.close(); 47 | done(); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }); 53 | 54 | describe('query', function() { 55 | 56 | it('should build 1 directory and 1 file (*.json)', function(done) { 57 | 58 | backup({ 59 | uri: URI, 60 | root: ROOT, 61 | collections: [ 'logins' ], 62 | parser: 'json', 63 | metadata: true, 64 | query: { 65 | _id: DOCS[Object.keys(DOCS)[0]]._id 66 | }, 67 | callback: function(err) { 68 | 69 | assert.ifError(err); 70 | setTimeout(function() { 71 | 72 | fs.readdirSync(ROOT).forEach(function(first) { // database 73 | 74 | var database = ROOT + '/' + first; 75 | assert.equal(fs.statSync(database).isDirectory(), true); 76 | var second = fs.readdirSync(database); 77 | assert.equal(second.length, 2); 78 | assert.equal(second[1], 'logins'); 79 | fs.unlinkSync(database + '/.metadata/' + second[1]); 80 | var collection = database + '/' + second[1]; 81 | if (fs.statSync(collection).isDirectory() === false) { 82 | return; 83 | } 84 | var docs = fs.readdirSync(collection); 85 | assert.equal(docs.length, 1, 'forget?'); 86 | var third = docs[0]; 87 | var document = collection + '/' + third; 88 | assert.equal(extname(third), '.json'); 89 | var _id = third.split('.json')[0]; 90 | var data = require(document); 91 | // JSON error on id and Date 92 | assert.equal(data._id, DOCS[_id]._id); 93 | assert.equal(data._id, DOCS[Object.keys(DOCS)[0]]._id); 94 | fs.unlinkSync(document); 95 | fs.rmdirSync(collection); 96 | fs.rmdirSync(database + '/.metadata/'); 97 | fs.rmdirSync(database); 98 | }); 99 | done(); 100 | }, 500); 101 | } 102 | }); 103 | }); 104 | it('should build 1 directory and 1 file (*.bson)', function(done) { 105 | 106 | backup({ 107 | uri: URI, 108 | root: ROOT, 109 | collections: [ 'logins' ], 110 | parser: 'bson', 111 | metadata: true, 112 | query: { 113 | _id: DOCS[Object.keys(DOCS)[0]]._id 114 | }, 115 | callback: function(err) { 116 | 117 | assert.ifError(err); 118 | setTimeout(function() { 119 | 120 | fs.readdirSync(ROOT).forEach(function(first) { // database 121 | 122 | var database = ROOT + '/' + first; 123 | assert.equal(fs.statSync(database).isDirectory(), true); 124 | var second = fs.readdirSync(database); 125 | assert.equal(second.length, 2); 126 | assert.equal(second[1], 'logins'); 127 | fs.unlinkSync(database + '/.metadata/' + second[1]); 128 | var collection = database + '/' + second[1]; 129 | if (fs.statSync(collection).isDirectory() === false) { 130 | return; 131 | } 132 | var docs = fs.readdirSync(collection); 133 | assert.equal(docs.length, 1, 'forget?'); 134 | var third = docs[0]; 135 | var document = collection + '/' + third; 136 | assert.equal(extname(third), '.bson'); 137 | var _id = third.split('.bson')[0]; 138 | var data = BSON.deserialize(fs.readFileSync(document, { 139 | encoding: null 140 | })); 141 | assert.deepEqual(data, DOCS[_id]); 142 | assert.equal(String(data._id), DOCS[Object.keys(DOCS)[0]]._id); 143 | fs.unlinkSync(document); 144 | fs.rmdirSync(collection); 145 | fs.rmdirSync(database + '/.metadata/'); 146 | fs.rmdirSync(database); 147 | }); 148 | done(); 149 | }, 500); 150 | } 151 | }); 152 | }); 153 | }); 154 | 155 | describe('collections', function() { 156 | 157 | it('should build 1 directory (*.json)', function(done) { 158 | 159 | backup({ 160 | uri: URI, 161 | root: ROOT, 162 | collections: [ 'logins' ], 163 | parser: 'json', 164 | metadata: true, 165 | callback: function(err) { 166 | 167 | assert.ifError(err); 168 | setTimeout(function() { 169 | 170 | fs.readdirSync(ROOT).forEach(function(first) { // database 171 | 172 | var database = ROOT + '/' + first; 173 | assert.equal(fs.statSync(database).isDirectory(), true); 174 | var second = fs.readdirSync(database); 175 | assert.equal(second.length, 2); 176 | assert.equal(second[1], 'logins'); 177 | fs.unlinkSync(database + '/.metadata/' + second[1]); 178 | var collection = database + '/' + second[1]; 179 | if (fs.statSync(collection).isDirectory() === false) { 180 | return; 181 | } 182 | var docs = fs.readdirSync(collection); 183 | assert.equal(docs.length, Object.keys(DOCS).length, 'forget?'); 184 | docs.forEach(function(third) { // document 185 | 186 | var document = collection + '/' + third; 187 | assert.equal(extname(third), '.json'); 188 | var _id = third.split('.json')[0]; 189 | var data = require(document); 190 | // JSON error on id and Date 191 | assert.equal(data._id, DOCS[_id]._id); 192 | fs.unlinkSync(document); 193 | }); 194 | fs.rmdirSync(collection); 195 | fs.rmdirSync(database + '/.metadata/'); 196 | fs.rmdirSync(database); 197 | }); 198 | done(); 199 | }, 500); 200 | } 201 | }); 202 | }); 203 | it('should build 1 directory (*.bson)', function(done) { 204 | 205 | backup({ 206 | uri: URI, 207 | root: ROOT, 208 | collections: [ 'logins' ], 209 | parser: 'bson', 210 | metadata: true, 211 | callback: function(err) { 212 | 213 | assert.ifError(err); 214 | setTimeout(function() { 215 | 216 | fs.readdirSync(ROOT).forEach(function(first) { // database 217 | 218 | var database = ROOT + '/' + first; 219 | assert.equal(fs.statSync(database).isDirectory(), true); 220 | var second = fs.readdirSync(database); 221 | assert.equal(second.length, 2); 222 | assert.equal(second[1], 'logins'); 223 | fs.unlinkSync(database + '/.metadata/' + second[1]); 224 | var collection = database + '/' + second[1]; 225 | if (fs.statSync(collection).isDirectory() === false) { 226 | return; 227 | } 228 | var docs = fs.readdirSync(collection); 229 | assert.equal(docs.length, Object.keys(DOCS).length, 'forget?'); 230 | docs.forEach(function(third) { // document 231 | 232 | var document = collection + '/' + third; 233 | assert.equal(extname(third), '.bson'); 234 | var _id = third.split('.bson')[0]; 235 | var data = BSON.deserialize(fs.readFileSync(document, { 236 | encoding: null 237 | })); 238 | assert.deepEqual(data, DOCS[_id]); 239 | fs.unlinkSync(document); 240 | }); 241 | fs.rmdirSync(collection); 242 | fs.rmdirSync(database + '/.metadata/'); 243 | fs.rmdirSync(database); 244 | }); 245 | done(); 246 | }, 500); 247 | } 248 | }); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /test/error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file error test 4 | * @module mongodb-backup 5 | * @subpackage test 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); 15 | var assert = require('assert'); 16 | 17 | /* 18 | * test module 19 | */ 20 | describe('error', function() { 21 | 22 | it('should return missing uri', function(done) { 23 | 24 | var mex = /missing uri option/; 25 | assert.throws(function() { 26 | 27 | backup(); 28 | }, mex); 29 | assert.throws(function() { 30 | 31 | backup({}); 32 | }, mex); 33 | assert.throws(function() { 34 | 35 | backup({ 36 | root: 'ciao' 37 | }); 38 | }, mex); 39 | done(); 40 | }); 41 | it('should return parser root', function(done) { 42 | 43 | var mex = /missing parser option/; 44 | assert.throws(function() { 45 | 46 | backup({ 47 | uri: 'ciao', 48 | root: 'ciao', 49 | parser: 'ciao' 50 | }); 51 | }, mex); 52 | done(); 53 | }); 54 | it('should return wrong uri', function(done) { 55 | 56 | var mex = /invalid schema, expected mongodb/; 57 | assert.throws(function() { 58 | 59 | backup({ 60 | uri: 'ciao', 61 | root: 'ciao' 62 | }); 63 | }, mex); 64 | done(); 65 | }); 66 | 67 | describe('root', function() { 68 | 69 | it('should return missing root', function(done) { 70 | 71 | var mex = /missing root option/; 72 | assert.throws(function() { 73 | 74 | backup({ 75 | uri: 'ciao' 76 | }); 77 | }, mex); 78 | done(); 79 | }); 80 | it('should return different error message (exists)', function(done) { 81 | 82 | var mex = /invalid schema, expected mongodb/; 83 | assert.throws(function() { 84 | 85 | backup({ 86 | uri: 'ciao', 87 | root: __dirname 88 | }); 89 | }, mex); 90 | done(); 91 | }); 92 | it('should return different error message (not file)', function(done) { 93 | 94 | var mex = /root option is not a directory/; 95 | assert.throws(function() { 96 | 97 | backup({ 98 | uri: 'ciao', 99 | root: __dirname + '/error.js' 100 | }); 101 | }, mex); 102 | done(); 103 | }); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /test/issue10.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file issue #10 test 4 | * @module mongodb-backup 5 | * @subpackage test 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); 15 | var assert = require('assert'); 16 | var fs = require('fs'); 17 | var extname = require('path').extname; 18 | var mongodb = require('mongodb'); 19 | var bson = require('bson'); 20 | 21 | var client = mongodb.MongoClient; 22 | var BSON = new bson.BSON(); 23 | var MLong = mongodb.Long; 24 | var BLong = bson.Long; 25 | var Uri = process.env.URI; 26 | var Root = __dirname + '/dump'; 27 | var Collection = 'test_10'; 28 | 29 | /* 30 | * test module 31 | */ 32 | describe('issue10', function() { 33 | 34 | var NInt64, SInt64, NLong, SLong; 35 | 36 | describe('create new collection', function() { 37 | 38 | it('should create long number', function(done) { 39 | 40 | var long1 = MLong.fromNumber(100); 41 | var long2 = BLong.fromNumber(100); 42 | assert.deepEqual(long1, long2); 43 | var long1 = MLong.fromString('100'); 44 | var long2 = BLong.fromString('100'); 45 | assert.deepEqual(long1, long2); 46 | 47 | NInt64 = 1000576093407275579; 48 | SInt64 = '1000576093407275579'; 49 | NLong = MLong.fromNumber(NInt64); 50 | SLong = MLong.fromString(SInt64); 51 | 52 | done(); 53 | }); 54 | it('should create "' + Collection + '" collection', function(done) { 55 | 56 | client.connect(Uri, function(err, db) { 57 | 58 | assert.ifError(err); 59 | db.createCollection(Collection, function(err, collection) { 60 | 61 | assert.ifError(err); 62 | collection.remove({}, function(err, result) { // remove previous data 63 | 64 | assert.ifError(err); 65 | collection.insert([ { 66 | _id: 'nint64', 67 | d: NInt64, 68 | t: 'foo1' 69 | }, { 70 | _id: 'sint64', 71 | d: SInt64, 72 | t: 'foo2' 73 | }, { 74 | _id: 'nlong', 75 | d: NLong, 76 | t: 'foo3' 77 | }, { 78 | _id: 'slong', 79 | d: SLong, 80 | t: 'foo4' 81 | } ], function(err, result) { 82 | 83 | assert.ifError(err); 84 | assert.equal(result.result.ok, 1); 85 | assert.equal(result.result.n, 4); 86 | db.close(); 87 | done(); 88 | }); 89 | }); 90 | }); 91 | }); 92 | }); 93 | }); 94 | 95 | describe('backup', function() { 96 | 97 | it('should build 1 directory and 4 files', function(done) { 98 | 99 | backup({ 100 | uri: Uri, 101 | root: Root, 102 | collections: [ Collection ], 103 | callback: function(err) { 104 | 105 | assert.ifError(err); 106 | setTimeout(done, 500); 107 | } 108 | }); 109 | }); 110 | }); 111 | 112 | describe('deserialize', function() { 113 | 114 | var database, collection; 115 | var nint64_file, nlong_file, sint64_file, slong_file; 116 | 117 | it('should find 2 files', function(done) { 118 | 119 | var first = fs.readdirSync(Root); 120 | assert.equal(first.length, 1, 'database'); 121 | 122 | database = Root + '/' + first[0]; 123 | assert.equal(fs.statSync(database).isDirectory(), true); 124 | 125 | var second = fs.readdirSync(database); 126 | assert.equal(second.length, 1, 'collection'); 127 | assert.equal(second[0], Collection); 128 | 129 | collection = database + '/' + second[0]; 130 | assert.equal(fs.statSync(collection).isDirectory(), true); 131 | 132 | var docs = fs.readdirSync(collection); 133 | assert.equal(docs.length, 4); 134 | nint64_file = collection + '/' + docs[0]; 135 | nlong_file = collection + '/' + docs[1]; 136 | sint64_file = collection + '/' + docs[2]; 137 | slong_file = collection + '/' + docs[3]; 138 | 139 | docs.forEach(function(file) { 140 | 141 | var p = collection + '/' + file; 142 | assert.equal(fs.statSync(p).isFile(), true); 143 | assert.equal(extname(p), '.bson'); 144 | }); 145 | 146 | done(); 147 | }); 148 | it('should deserialize nint64 file', function(done) { 149 | 150 | var data = BSON.deserialize(fs.readFileSync(nint64_file)); 151 | assert.strictEqual(data._id, 'nint64'); 152 | assert.deepEqual(data.d, NInt64); 153 | assert.strictEqual(data.t, 'foo1'); 154 | fs.unlink(nint64_file, done); 155 | }); 156 | it('should deserialize sint64 file', function(done) { 157 | 158 | var data = BSON.deserialize(fs.readFileSync(sint64_file)); 159 | assert.strictEqual(data._id, 'sint64'); 160 | assert.deepEqual(data.d, SInt64); 161 | assert.strictEqual(data.t, 'foo2'); 162 | fs.unlink(sint64_file, done); 163 | }); 164 | it('should deserialize nlong file', function(done) { 165 | 166 | var data = BSON.deserialize(fs.readFileSync(nlong_file)); 167 | assert.strictEqual(data._id, 'nlong'); 168 | assert.deepEqual(data.d, NLong); 169 | assert.strictEqual(data.t, 'foo3'); 170 | fs.unlink(nlong_file, done); 171 | }); 172 | it('should deserialize slong file', function(done) { 173 | 174 | var data = BSON.deserialize(fs.readFileSync(slong_file)); 175 | assert.strictEqual(data._id, 'slong'); 176 | assert.deepEqual(data.d, SLong); 177 | assert.strictEqual(data.t, 'foo4'); 178 | fs.unlink(slong_file, done); 179 | }); 180 | it('should remove dirs', function(done) { 181 | 182 | fs.rmdirSync(collection); 183 | fs.rmdirSync(database); 184 | done(); 185 | }); 186 | }); 187 | 188 | }); 189 | -------------------------------------------------------------------------------- /test/parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file parser test 4 | * @module mongodb-backup 5 | * @subpackage test 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); 15 | var assert = require('assert'); 16 | var URI = process.env.URI; 17 | 18 | /* 19 | * test module 20 | */ 21 | describe('parser', function() { 22 | 23 | var ROOT = __dirname + '/dump'; 24 | 25 | it('should check custom parser', function(done) { 26 | 27 | var c = 0; 28 | backup({ 29 | uri: URI, 30 | root: ROOT, 31 | collections: [ 'logins' ], 32 | parser: function(docs, name, next) { 33 | 34 | c++; 35 | assert.equal(Array.isArray(docs), false); 36 | assert.equal(typeof name, 'string'); 37 | assert.equal(typeof next, 'undefined'); 38 | // next(); 39 | }, 40 | callback: function(err) { 41 | 42 | assert.ifError(err); 43 | assert.equal(c > 0, true); 44 | done(); 45 | } 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file stream test 4 | * @module mongodb-backup 5 | * @subpackage test 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); 15 | var assert = require('assert'); 16 | var request = require('supertest'); 17 | var fs = require('fs'); 18 | var http = require('http'); 19 | var URI = process.env.URI; 20 | 21 | /* 22 | * test module 23 | */ 24 | describe('stream', function() { 25 | 26 | var ROOT = __dirname + '/dump'; 27 | 28 | describe('tar', function() { 29 | 30 | var app; 31 | var path0 = ROOT + '/from_web.tar'; 32 | var path1 = ROOT + '/from_file.tar'; 33 | 34 | describe('web', function() { 35 | 36 | it('should check that tar file not exist before test', function(done) { 37 | 38 | assert.equal(fs.existsSync(path0), false); 39 | done(); 40 | }); 41 | it('should create a web application', function(done) { 42 | 43 | app = http.createServer(function(req, res) { 44 | 45 | res.writeHead(200, { 46 | 'Content-Type': 'application/x-tar' 47 | }); 48 | 49 | backup({ 50 | collections: [ 'logins', 'auths', 'wrong_name' ], 51 | uri: URI, 52 | stream: res 53 | }); 54 | 55 | }); 56 | done(); 57 | }); 58 | it('should send a request to web and write a tar file', function(done) { 59 | 60 | request(app).get('/').expect('Content-Type', /tar/).expect(200).end( 61 | function(err, res) { 62 | 63 | assert.ifError(err); 64 | fs.writeFile(path0, res.text, done); 65 | }); 66 | }); 67 | it('should check that buffer dir not exist', function(done) { 68 | 69 | var paths = __dirname + '/../dump'; 70 | assert.equal(fs.existsSync(paths), true); 71 | assert.equal(fs.readdirSync(paths).length, 0, 'empty dir'); 72 | done(); 73 | }); 74 | }); 75 | 76 | describe('file', function() { 77 | 78 | it('should check that tar file not exist before test', function(done) { 79 | 80 | assert.equal(fs.existsSync(path1), false); 81 | done(); 82 | }); 83 | it('should make a tar file', function(done) { 84 | 85 | backup({ 86 | collections: [ 'logins', 'auths', 'wrong_name' ], 87 | uri: URI, 88 | root: ROOT, 89 | tar: 'from_file.tar', 90 | callback: function(err) { 91 | 92 | assert.ifError(err); 93 | assert.equal(fs.existsSync(path1), true); 94 | done(); 95 | } 96 | }); 97 | }); 98 | it('should check that buffer dir not exist', function(done) { 99 | 100 | var paths = __dirname + '/../dump'; 101 | assert.equal(fs.existsSync(paths), true); 102 | assert.equal(fs.readdirSync(paths).length, 0, 'empty dir'); 103 | done(); 104 | }); 105 | }); 106 | 107 | describe('end', function() { 108 | 109 | it('should delete this 2 files', function(done) { 110 | 111 | fs.unlinkSync(path0); 112 | fs.unlinkSync(path1); 113 | done(); 114 | }); 115 | }); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /test/structure.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @file structure test 4 | * @module mongodb-backup 5 | * @subpackage test 6 | * @version 0.0.1 7 | * @author hex7c0 8 | * @license GPLv3 9 | */ 10 | 11 | /* 12 | * initialize module 13 | */ 14 | var backup = require('..'); 15 | var assert = require('assert'); 16 | var fs = require('fs'); 17 | var extname = require('path').extname; 18 | var URI = process.env.URI; 19 | 20 | var pad = function(val, len) { 21 | 22 | var val = String(val); 23 | var len = len || 2; 24 | while (val.length < len) { 25 | val = '0' + val; 26 | } 27 | return val; 28 | }; 29 | 30 | /* 31 | * test module 32 | */ 33 | describe('structure', function() { 34 | 35 | var ROOT = __dirname + '/dump'; 36 | 37 | describe('with query', function() { 38 | 39 | describe('errors', function() { 40 | 41 | it('should return error beacause collection does not exist', 42 | function(done) { 43 | 44 | backup({ 45 | uri: URI, 46 | root: ROOT, 47 | collections: [ 'foobar' ], 48 | callback: function(err) { 49 | 50 | assert.notEqual(err, null); 51 | assert.ok(/does not exist/.test(err.message)); 52 | fs.readdirSync(ROOT).forEach(function(first) { // database 53 | 54 | var database = ROOT + '/' + first; 55 | fs.stat(database + '/foobar', function(err) { 56 | 57 | assert.notEqual(err, null); 58 | // assert.ok(/no such file or directory/.test(err.message)); 59 | done(); 60 | }); 61 | }); 62 | } 63 | }); 64 | }); 65 | it('should return error beacause collections does not exist', 66 | function(done) { 67 | 68 | backup({ 69 | uri: URI, 70 | root: ROOT, 71 | collections: [ 'foo', 'bar' ], 72 | callback: function(err) { 73 | 74 | assert.notEqual(err, null); 75 | assert.ok(/does not exist/.test(err.message)); 76 | fs.readdirSync(ROOT).forEach(function(first) { // database 77 | 78 | var database = ROOT + '/' + first; 79 | fs.stat(database + '/foo', function(err) { 80 | 81 | assert.notEqual(err, null); 82 | // assert.ok(/no such file or directory/.test(err.message)); 83 | fs.stat(database + '/bar', function(err) { 84 | 85 | assert.notEqual(err, null); 86 | // assert.ok(/no such file or directory/.test(err.message)); 87 | done(); 88 | }); 89 | }); 90 | }); 91 | } 92 | }); 93 | }); 94 | }); 95 | 96 | describe('collections', function() { 97 | 98 | it('should build 1 directory (*.json)', function(done) { 99 | 100 | backup({ 101 | uri: URI, 102 | root: ROOT, 103 | collections: [ 'logins', 'auths' ], 104 | parser: 'json', 105 | callback: function(err) { 106 | 107 | assert.ifError(err); 108 | setTimeout(function() { 109 | 110 | fs.readdirSync(ROOT).forEach(function(first) { // database 111 | 112 | var database = ROOT + '/' + first; 113 | assert.equal(fs.statSync(database).isDirectory(), true); 114 | var second = fs.readdirSync(database); 115 | assert.equal(second.length, 2); 116 | assert.equal(second[0], 'auths'); 117 | assert.equal(second[1], 'logins'); 118 | 119 | var collection = database + '/' + second[0]; 120 | assert.ok(fs.statSync(collection).isDirectory()); 121 | fs.readdirSync(collection).forEach(function(third) { // document 122 | 123 | assert.equal(extname(third), '.json'); 124 | var document = collection + '/' + third; 125 | fs.unlinkSync(document); 126 | }); 127 | fs.rmdirSync(collection); 128 | 129 | var collection = database + '/' + second[1]; 130 | assert.ok(fs.statSync(collection).isDirectory()); 131 | fs.readdirSync(collection).forEach(function(third) { // document 132 | 133 | assert.equal(extname(third), '.json'); 134 | var document = collection + '/' + third; 135 | fs.unlinkSync(document); 136 | }); 137 | fs.rmdirSync(collection); 138 | 139 | fs.rmdirSync(database); 140 | }); 141 | done(); 142 | }, 500); 143 | } 144 | }); 145 | }); 146 | it('should build 1 directory (*.bson)', function(done) { 147 | 148 | backup({ 149 | uri: URI, 150 | root: ROOT, 151 | collections: [ 'logins', 'auths' ], 152 | parser: 'bson', 153 | callback: function(err) { 154 | 155 | assert.ifError(err); 156 | setTimeout(function() { 157 | 158 | fs.readdirSync(ROOT).forEach(function(first) { // database 159 | 160 | var database = ROOT + '/' + first; 161 | assert.equal(fs.statSync(database).isDirectory(), true); 162 | var second = fs.readdirSync(database); 163 | assert.equal(second.length, 2); 164 | assert.equal(second[0], 'auths'); 165 | assert.equal(second[1], 'logins'); 166 | 167 | var collection = database + '/' + second[0]; 168 | assert.ok(fs.statSync(collection).isDirectory()); 169 | fs.readdirSync(collection).forEach(function(third) { // document 170 | 171 | assert.equal(extname(third), '.bson'); 172 | var document = collection + '/' + third; 173 | fs.unlinkSync(document); 174 | }); 175 | fs.rmdirSync(collection); 176 | 177 | var collection = database + '/' + second[1]; 178 | assert.ok(fs.statSync(collection).isDirectory()); 179 | fs.readdirSync(collection).forEach(function(third) { // document 180 | 181 | assert.equal(extname(third), '.bson'); 182 | var document = collection + '/' + third; 183 | fs.unlinkSync(document); 184 | }); 185 | fs.rmdirSync(collection); 186 | 187 | fs.rmdirSync(database); 188 | }); 189 | done(); 190 | }, 500); 191 | } 192 | }); 193 | }); 194 | }); 195 | 196 | describe('parser', function() { 197 | 198 | it('should build any directories (*.json)', function(done) { 199 | 200 | backup({ 201 | uri: URI, 202 | root: ROOT, 203 | parser: 'json', 204 | callback: function(err) { 205 | 206 | assert.ifError(err); 207 | setTimeout(function() { 208 | 209 | fs.readdirSync(ROOT).forEach(function(first) { // database 210 | 211 | var database = ROOT + '/' + first; 212 | assert.equal(fs.statSync(database).isDirectory(), true); 213 | fs.readdirSync(database).forEach(function(second) { // collection 214 | 215 | var collection = database + '/' + second; 216 | assert.ok(fs.statSync(collection).isDirectory()); 217 | fs.readdirSync(collection).forEach(function(third) { // document 218 | 219 | assert.equal(extname(third), '.json'); 220 | var document = collection + '/' + third; 221 | fs.unlinkSync(document); 222 | }); 223 | fs.rmdirSync(collection); 224 | }); 225 | fs.rmdirSync(database); 226 | }); 227 | done(); 228 | }, 500); 229 | } 230 | }); 231 | }); 232 | it('should build any directories (*.bson)', function(done) { 233 | 234 | backup({ 235 | uri: URI, 236 | root: ROOT, 237 | parser: 'bson', 238 | callback: function(err) { 239 | 240 | assert.ifError(err); 241 | setTimeout(function() { 242 | 243 | fs.readdirSync(ROOT).forEach(function(first) { // database 244 | 245 | var database = ROOT + '/' + first; 246 | assert.equal(fs.statSync(database).isDirectory(), true); 247 | fs.readdirSync(database).forEach(function(second) { // collection 248 | 249 | var collection = database + '/' + second; 250 | assert.ok(fs.statSync(collection).isDirectory()); 251 | fs.readdirSync(collection).forEach(function(third) { // document 252 | 253 | assert.equal(extname(third), '.bson'); 254 | var document = collection + '/' + third; 255 | fs.unlinkSync(document); 256 | }); 257 | fs.rmdirSync(collection); 258 | }); 259 | fs.rmdirSync(database); 260 | }); 261 | done(); 262 | }, 500); 263 | } 264 | }); 265 | }); 266 | }); 267 | 268 | describe('tar', function() { 269 | 270 | var path = ROOT + '/t1.tar'; 271 | it('should check that tar file not exist before test', function(done) { 272 | 273 | assert.equal(fs.existsSync(path), false); 274 | done(); 275 | }); 276 | it('should make a tar file', function(done) { 277 | 278 | backup({ 279 | uri: URI, 280 | root: ROOT, 281 | tar: 't1.tar', 282 | callback: function(err) { 283 | 284 | assert.ifError(err); 285 | assert.equal(fs.existsSync(path), true); 286 | fs.unlink(path, done); 287 | } 288 | }); 289 | }); 290 | it('should check that buffer dir not exist', function(done) { 291 | 292 | var paths = __dirname + '/../dump'; 293 | assert.equal(fs.existsSync(paths), true); // stay alive 294 | assert.equal(fs.readdirSync(paths).length, 0, 'empty dir'); 295 | done(); 296 | }); 297 | }); 298 | 299 | describe('logger', function() { 300 | 301 | var l = 'l1.log'; 302 | var date = new Date(); 303 | var dailyF = date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) 304 | + '-' + pad(date.getUTCDate()) + '.' + l; 305 | it('should check that log file not exist before test', function(done) { 306 | 307 | assert.equal(fs.existsSync(l), false); 308 | assert.equal(fs.existsSync(dailyF), false); 309 | done(); 310 | }); 311 | it('should make a log file', function(done) { 312 | 313 | backup({ 314 | uri: URI, 315 | root: ROOT, 316 | logger: l, 317 | callback: function(err) { 318 | 319 | setTimeout(function() { 320 | 321 | assert.ifError(err); 322 | assert.equal(fs.existsSync(dailyF), true); 323 | fs.unlink(dailyF, done); 324 | }, 500); 325 | } 326 | }); 327 | }); 328 | it('should remove dirs', function(done) { 329 | 330 | fs.readdirSync(ROOT).forEach(function(first) { // database 331 | 332 | var database = ROOT + '/' + first; 333 | assert.equal(fs.statSync(database).isDirectory(), true); 334 | fs.readdirSync(database).forEach(function(second) { // collection 335 | 336 | var collection = database + '/' + second; 337 | assert.ok(fs.statSync(collection).isDirectory()); 338 | fs.readdirSync(collection).forEach(function(third) { // document 339 | 340 | assert.equal(extname(third), '.bson'); 341 | var document = collection + '/' + third; 342 | fs.unlinkSync(document); 343 | }); 344 | fs.rmdirSync(collection); 345 | }); 346 | fs.rmdirSync(database); 347 | }); 348 | done(); 349 | }); 350 | }); 351 | }); 352 | 353 | describe('with parallelCollectionScan', function() { 354 | 355 | describe('errors', function() { 356 | 357 | it('should return error beacause collection does not exist', 358 | function(done) { 359 | 360 | backup({ 361 | uri: URI, 362 | root: ROOT, 363 | collections: [ 'foobar' ], 364 | numCursors: 2, 365 | callback: function(err) { 366 | 367 | assert.notEqual(err, null); 368 | assert.ok(/does not exist/.test(err.message)); 369 | fs.readdirSync(ROOT).forEach(function(first) { // database 370 | 371 | var database = ROOT + '/' + first; 372 | fs.stat(database + '/foobar', function(err) { 373 | 374 | assert.notEqual(err, null); 375 | // assert.ok(/no such file or directory/.test(err.message)); 376 | done(); 377 | }); 378 | }); 379 | } 380 | }); 381 | }); 382 | it('should return error beacause collections does not exist', 383 | function(done) { 384 | 385 | backup({ 386 | uri: URI, 387 | root: ROOT, 388 | collections: [ 'foo', 'bar' ], 389 | numCursors: 2, 390 | callback: function(err) { 391 | 392 | assert.notEqual(err, null); 393 | assert.ok(/does not exist/.test(err.message)); 394 | fs.readdirSync(ROOT).forEach(function(first) { // database 395 | 396 | var database = ROOT + '/' + first; 397 | fs.stat(database + '/foo', function(err) { 398 | 399 | assert.notEqual(err, null); 400 | // assert.ok(/no such file or directory/.test(err.message)); 401 | fs.stat(database + '/bar', function(err) { 402 | 403 | assert.notEqual(err, null); 404 | // assert.ok(/no such file or directory/.test(err.message)); 405 | done(); 406 | }); 407 | }); 408 | }); 409 | } 410 | }); 411 | }); 412 | }); 413 | 414 | describe('collections', function() { 415 | 416 | it('should build 1 directory (*.json)', function(done) { 417 | 418 | backup({ 419 | uri: URI, 420 | root: ROOT, 421 | collections: [ 'logins', 'auths' ], 422 | parser: 'json', 423 | numCursors: 2, 424 | callback: function(err) { 425 | 426 | assert.ifError(err); 427 | setTimeout(function() { 428 | 429 | fs.readdirSync(ROOT).forEach(function(first) { // database 430 | 431 | var database = ROOT + '/' + first; 432 | assert.equal(fs.statSync(database).isDirectory(), true); 433 | var second = fs.readdirSync(database); 434 | assert.equal(second.length, 2); 435 | assert.equal(second[0], 'auths'); 436 | assert.equal(second[1], 'logins'); 437 | 438 | var collection = database + '/' + second[0]; 439 | assert.ok(fs.statSync(collection).isDirectory()); 440 | fs.readdirSync(collection).forEach(function(third) { // document 441 | 442 | assert.equal(extname(third), '.json'); 443 | var document = collection + '/' + third; 444 | fs.unlinkSync(document); 445 | }); 446 | fs.rmdirSync(collection); 447 | 448 | var collection = database + '/' + second[1]; 449 | assert.ok(fs.statSync(collection).isDirectory()); 450 | fs.readdirSync(collection).forEach(function(third) { // document 451 | 452 | assert.equal(extname(third), '.json'); 453 | var document = collection + '/' + third; 454 | fs.unlinkSync(document); 455 | }); 456 | fs.rmdirSync(collection); 457 | 458 | fs.rmdirSync(database); 459 | }); 460 | done(); 461 | }, 500); 462 | } 463 | }); 464 | }); 465 | it('should build 1 directory (*.bson)', function(done) { 466 | 467 | backup({ 468 | uri: URI, 469 | root: ROOT, 470 | collections: [ 'logins', 'auths' ], 471 | parser: 'bson', 472 | numCursors: 2, 473 | callback: function(err) { 474 | 475 | assert.ifError(err); 476 | setTimeout(function() { 477 | 478 | fs.readdirSync(ROOT).forEach(function(first) { // database 479 | 480 | var database = ROOT + '/' + first; 481 | assert.equal(fs.statSync(database).isDirectory(), true); 482 | var second = fs.readdirSync(database); 483 | assert.equal(second.length, 2); 484 | assert.equal(second[0], 'auths'); 485 | assert.equal(second[1], 'logins'); 486 | 487 | var collection = database + '/' + second[0]; 488 | assert.ok(fs.statSync(collection).isDirectory()); 489 | fs.readdirSync(collection).forEach(function(third) { // document 490 | 491 | assert.equal(extname(third), '.bson'); 492 | var document = collection + '/' + third; 493 | fs.unlinkSync(document); 494 | }); 495 | fs.rmdirSync(collection); 496 | 497 | var collection = database + '/' + second[1]; 498 | assert.ok(fs.statSync(collection).isDirectory()); 499 | fs.readdirSync(collection).forEach(function(third) { // document 500 | 501 | assert.equal(extname(third), '.bson'); 502 | var document = collection + '/' + third; 503 | fs.unlinkSync(document); 504 | }); 505 | fs.rmdirSync(collection); 506 | 507 | fs.rmdirSync(database); 508 | }); 509 | done(); 510 | }, 500); 511 | } 512 | }); 513 | }); 514 | }); 515 | 516 | describe('parser', function() { 517 | 518 | it('should build any directories (*.json)', function(done) { 519 | 520 | backup({ 521 | uri: URI, 522 | root: ROOT, 523 | parser: 'json', 524 | numCursors: 2, 525 | callback: function(err) { 526 | 527 | assert.ifError(err); 528 | setTimeout(function() { 529 | 530 | fs.readdirSync(ROOT).forEach(function(first) { // database 531 | 532 | var database = ROOT + '/' + first; 533 | assert.equal(fs.statSync(database).isDirectory(), true); 534 | fs.readdirSync(database).forEach(function(second) { // collection 535 | 536 | var collection = database + '/' + second; 537 | assert.ok(fs.statSync(collection).isDirectory()); 538 | fs.readdirSync(collection).forEach(function(third) { // document 539 | 540 | assert.equal(extname(third), '.json'); 541 | var document = collection + '/' + third; 542 | fs.unlinkSync(document); 543 | }); 544 | fs.rmdirSync(collection); 545 | }); 546 | fs.rmdirSync(database); 547 | }); 548 | done(); 549 | }, 500); 550 | } 551 | }); 552 | }); 553 | it('should build any directories (*.bson)', function(done) { 554 | 555 | backup({ 556 | uri: URI, 557 | root: ROOT, 558 | parser: 'bson', 559 | numCursors: 2, 560 | callback: function(err) { 561 | 562 | assert.ifError(err); 563 | setTimeout(function() { 564 | 565 | fs.readdirSync(ROOT).forEach(function(first) { // database 566 | 567 | var database = ROOT + '/' + first; 568 | assert.equal(fs.statSync(database).isDirectory(), true); 569 | fs.readdirSync(database).forEach(function(second) { // collection 570 | 571 | var collection = database + '/' + second; 572 | assert.ok(fs.statSync(collection).isDirectory()); 573 | fs.readdirSync(collection).forEach(function(third) { // document 574 | 575 | assert.equal(extname(third), '.bson'); 576 | var document = collection + '/' + third; 577 | fs.unlinkSync(document); 578 | }); 579 | fs.rmdirSync(collection); 580 | }); 581 | fs.rmdirSync(database); 582 | }); 583 | done(); 584 | }, 500); 585 | } 586 | }); 587 | }); 588 | }); 589 | 590 | describe('tar', function() { 591 | 592 | var path = ROOT + '/t2.tar'; 593 | it('should check that tar file not exist before test', function(done) { 594 | 595 | assert.equal(fs.existsSync(path), false); 596 | done(); 597 | }); 598 | it('should make a tar file', function(done) { 599 | 600 | backup({ 601 | uri: URI, 602 | root: ROOT, 603 | tar: 't2.tar', 604 | numCursors: 2, 605 | callback: function(err) { 606 | 607 | assert.ifError(err); 608 | assert.equal(fs.existsSync(path), true); 609 | fs.unlink(path, done); 610 | } 611 | }); 612 | }); 613 | it('should check that buffer dir not exist', function(done) { 614 | 615 | var paths = __dirname + '/../dump'; 616 | assert.equal(fs.existsSync(paths), true); // stay alive 617 | assert.equal(fs.readdirSync(paths).length, 0, 'empty dir'); 618 | done(); 619 | }); 620 | }); 621 | 622 | describe('logger', function() { 623 | 624 | var l = 'l2.log'; 625 | var date = new Date(); 626 | var dailyF = date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) 627 | + '-' + pad(date.getUTCDate()) + '.' + l; 628 | it('should check that log file not exist before test', function(done) { 629 | 630 | assert.equal(fs.existsSync(l), false); 631 | assert.equal(fs.existsSync(dailyF), false); 632 | done(); 633 | }); 634 | it('should make a log file', function(done) { 635 | 636 | backup({ 637 | uri: URI, 638 | root: ROOT, 639 | logger: l, 640 | numCursors: 2, 641 | callback: function(err) { 642 | 643 | setTimeout(function() { 644 | 645 | assert.ifError(err); 646 | assert.equal(fs.existsSync(dailyF), true); 647 | fs.unlink(dailyF, done); 648 | }, 500); 649 | } 650 | }); 651 | }); 652 | it('should remove dirs', function(done) { 653 | 654 | fs.readdirSync(ROOT).forEach(function(first) { // database 655 | 656 | var database = ROOT + '/' + first; 657 | assert.equal(fs.statSync(database).isDirectory(), true); 658 | fs.readdirSync(database).forEach(function(second) { // collection 659 | 660 | var collection = database + '/' + second; 661 | assert.ok(fs.statSync(collection).isDirectory()); 662 | fs.readdirSync(collection).forEach(function(third) { // document 663 | 664 | assert.equal(extname(third), '.bson'); 665 | var document = collection + '/' + third; 666 | fs.unlinkSync(document); 667 | }); 668 | fs.rmdirSync(collection); 669 | }); 670 | fs.rmdirSync(database); 671 | }); 672 | done(); 673 | }); 674 | }); 675 | }); 676 | }); 677 | --------------------------------------------------------------------------------