1 | var fs = require('fs');
|
2 | var path = require('path');
|
3 | var util = require('util');
|
4 |
|
5 | var xtend = require('xtend');
|
6 | var camelize = require('camelize');
|
7 | var optimist = require('optimist');
|
8 |
|
9 | var OPTIONS = {
|
10 | config: {
|
11 | describe: 'Specify a JSON config file to use as defaults',
|
12 | type: 'string'
|
13 | },
|
14 | update: {
|
15 | describe: 'The update mode: dummy, query or document (see documentation for more details)',
|
16 | type: 'string',
|
17 | default: 'document'
|
18 | },
|
19 | 'dry-run': {
|
20 | describe: 'Run patch without modifying data (same as --update dummy, overwrites --update option)',
|
21 | type: 'string'
|
22 | },
|
23 | db: {
|
24 | describe: 'Connection string for application database',
|
25 | type: 'string'
|
26 | },
|
27 | 'log-db': {
|
28 | describe: 'Connection string for log database',
|
29 | type: 'string'
|
30 | },
|
31 | parallel: {
|
32 | describe: 'Specify a parallelism level for the patch. Defaults to 1',
|
33 | type: 'string'
|
34 | },
|
35 | output: {
|
36 | describe: 'Output progress while runing the patch',
|
37 | type: 'boolean',
|
38 | default: true
|
39 | },
|
40 | force: {
|
41 | describe: 'Force a run without providing a log db',
|
42 | type: 'boolean'
|
43 | },
|
44 | version: {
|
45 | describe: 'Prints version',
|
46 | type: 'boolean'
|
47 | },
|
48 | 'diff-object': {
|
49 | describe: 'Use objects instead of arrays in document diff',
|
50 | type: 'boolean',
|
51 | default: false
|
52 | }
|
53 | };
|
54 |
|
55 | var OPTION_KEYS = Object.keys(OPTIONS).reduce(function(acc, key) {
|
56 | acc[camelize(key)] = true;
|
57 | return acc;
|
58 | }, {});
|
59 |
|
60 | var cmd = optimist()
|
61 | .usage('Usage: $0 [patch] [options]')
|
62 | .options(OPTIONS);
|
63 |
|
64 | var error = function(name) {
|
65 | var args = Array.prototype.slice.call(arguments, 1);
|
66 | return { option: name, message: util.format.apply(null, args) };
|
67 | };
|
68 |
|
69 | var version = function(argv) {
|
70 | var v = require('../../package').version;
|
71 | return util.format('mongopatch v%s', v);
|
72 | };
|
73 |
|
74 | var validate = function(patch, options) {
|
75 | if (!patch) {
|
76 | return error('patch', 'Patch path required');
|
77 | }
|
78 | if (!fs.existsSync(patch)) {
|
79 | return error('patch', 'Cannot find patch with path "%s"', patch);
|
80 | }
|
81 |
|
82 | var invalidOptions = Object.keys(options).filter(function(arg) {
|
83 | return !OPTION_KEYS.hasOwnProperty(arg);
|
84 | });
|
85 |
|
86 | if (invalidOptions.length) {
|
87 | var option = invalidOptions.shift();
|
88 | return error(option, 'Unknown option: %s', option);
|
89 | }
|
90 |
|
91 | if (!options.db) {
|
92 | return error('db', '--db option required');
|
93 | }
|
94 | if (!options.update) {
|
95 | return error('update', '--update option required');
|
96 | }
|
97 |
|
98 | if (['dummy', 'query', 'document'].indexOf(options.update) < 0) {
|
99 | return error('update', '--update option invalid');
|
100 | }
|
101 |
|
102 | if (options.update !== 'dummy' && !options.logDb && !options.force) {
|
103 | return error('logDb', '--log-db option required');
|
104 | }
|
105 | };
|
106 |
|
107 | var parse = function(argv) {
|
108 | var options = cmd.parse(argv);
|
109 | var patch = options._[0];
|
110 |
|
111 | patch = patch && path.resolve(process.cwd(), patch);
|
112 |
|
113 | delete options._;
|
114 | delete options.$0;
|
115 |
|
116 | options = camelize(options);
|
117 |
|
118 | options.dryRun = ('dryRun' in options) || options.update === 'dummy';
|
119 | if ('parallel' in options) {
|
120 | options.parallel = parseInt(options.parallel, 10) || 10;
|
121 | }
|
122 | if (options.dryRun) {
|
123 | options.update = 'dummy';
|
124 | }
|
125 |
|
126 | var conf = options.config ? JSON.parse(fs.readFileSync(options.config, 'utf-8')) : {};
|
127 | options = xtend(camelize(conf), options);
|
128 | var result = {
|
129 | patch: patch,
|
130 | options: options,
|
131 | help: cmd.help,
|
132 | version: version
|
133 | };
|
134 | var error = validate(patch, options);
|
135 | if (error) {
|
136 | result.error = error;
|
137 | }
|
138 | return result;
|
139 | };
|
140 |
|
141 | module.exports = function(argv) {
|
142 | argv = argv || process.argv.slice(2);
|
143 | return parse(argv);
|
144 | };
|