@contentstack/cli-cm-export 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,54 +18,58 @@ const { addlogs } = require('../util/log');
18
18
 
19
19
  let config = require('../../config/default');
20
20
  const stack = require('../util/contentstack-management-sdk');
21
- const assetConfig = config.modules.assets;
22
- const invalidKeys = assetConfig.invalidKeys;
23
- const httpClient = HttpClient.create();
24
-
25
- // The no. of assets fetched and processed in a batch
26
- const bLimit = assetConfig.batchLimit || 15;
27
-
28
- // The no. of asset files downloaded at a time
29
- const vLimit = assetConfig.downloadLimit || 3;
30
- let assetsFolderPath;
31
- let assetContentsFile;
32
- let folderJSONPath;
33
- let client;
34
-
35
- function ExportAssets() {
36
- this.assetContents = {};
37
- this.folderData = [];
38
- }
39
21
 
40
- ExportAssets.prototype = {
41
- start: function (credentialConfig) {
42
- this.assetContents = {};
43
- this.folderData = [];
44
- this.assetDownloadRetry = {};
45
- this.assetDownloadRetryLimit = 3;
46
- let self = this;
47
- config = credentialConfig;
48
- assetsFolderPath = path.resolve(config.data, config.branchName || '', assetConfig.dirName);
49
- assetContentsFile = path.resolve(assetsFolderPath, 'assets.json');
50
- folderJSONPath = path.resolve(assetsFolderPath, 'folders.json');
51
- client = stack.Client(config);
22
+ module.exports = class ExportAssets {
23
+ config
24
+ client
25
+ bLimit
26
+ vLimit
27
+ invalidKeys
28
+ folderJSONPath
29
+ folderData = []
30
+ assetsFolderPath
31
+ assetContents = {}
32
+ httpClient = HttpClient.create()
33
+ assetConfig = config.modules.assets
34
+
35
+ constructor(config) {
36
+ this.config = config
37
+ this.folderData = []
38
+ this.assetContents = {}
39
+ this.assetDownloadRetry = {}
40
+ this.assetDownloadRetryLimit = 3
41
+ this.invalidKeys = this.assetConfig.invalidKeys
42
+ this.bLimit = this.assetConfig.batchLimit || 15
43
+ this.vLimit = this.assetConfig.downloadLimit || config.fetchConcurrency || 3
44
+ }
45
+
46
+ start() {
47
+ const self = this
48
+ this.assetsFolderPath = path.resolve(this.config.data, this.config.branchName || '', this.assetConfig.dirName)
49
+ this.assetContentsFile = path.resolve(this.assetsFolderPath, 'assets.json')
50
+ this.folderJSONPath = path.resolve(this.assetsFolderPath, 'folders.json')
51
+ self.client = stack.Client(this.config)
52
+
53
+ addlogs(this.config, 'Starting assets export', 'success')
52
54
 
53
- addlogs(config, 'Starting assets export', 'success');
54
55
  // Create asset folder
55
- mkdirp.sync(assetsFolderPath);
56
+ mkdirp.sync(this.assetsFolderPath)
57
+
56
58
  return new Promise(function (resolve, reject) {
57
- //TBD: getting all the assets should have optimized
59
+ // TBD: getting all the assets should have optimized
58
60
  return self
59
61
  .getAssetCount()
60
62
  .then(function (count) {
63
+ const assetBatches = []
64
+
61
65
  if (typeof count !== 'number' || count === 0) {
62
- addlogs(config, 'No assets found', 'success');
63
- return resolve();
66
+ addlogs(self.config, 'No assets found', 'success')
67
+ return resolve()
64
68
  }
65
- const assetBatches = [];
66
- for (let i = 0; i <= count; i += bLimit) {
69
+ for (let i = 0; i <= count; i += self.bLimit) {
67
70
  assetBatches.push(i);
68
71
  }
72
+
69
73
  return Promise.map(
70
74
  assetBatches,
71
75
  function (batch) {
@@ -75,134 +79,145 @@ ExportAssets.prototype = {
75
79
  return Promise.map(
76
80
  assetsJSON,
77
81
  function (assetJSON) {
78
- return self
79
- .getVersionedAssetJSON(assetJSON.uid, assetJSON._version)
80
- .then(function () {
81
- self.assetContents[assetJSON.uid] = assetJSON;
82
- // log.success(chalk.white('The following asset has been downloaded successfully: ' +
83
- // assetJSON.uid))
84
- })
85
- .catch(function (error) {
86
- addlogs(
87
- config,
88
- chalk.red('The following asset failed to download\n' + JSON.stringify(assetJSON)),
89
- );
90
- addlogs(config, error, 'error');
91
- });
82
+ if (self.assetConfig.downloadVersionAssets) {
83
+ return self
84
+ .getVersionedAssetJSON(assetJSON.uid, assetJSON._version)
85
+ .then(function () {
86
+ self.assetContents[assetJSON.uid] = assetJSON;
87
+ }).catch(function (error) {
88
+ addlogs(
89
+ self.config,
90
+ chalk.red('The following asset failed to download\n' + JSON.stringify(assetJSON)),
91
+ )
92
+ addlogs(self.config, error, 'error')
93
+ })
94
+ } else {
95
+ return self.downloadAsset(assetJSON)
96
+ .then(function () {
97
+ self.assetContents[assetJSON.uid] = assetJSON
98
+ }).catch((err) => {
99
+ addlogs({ errorCode: (err && err.code), uid: assetJSON.uid }, `Asset download failed - ${assetJSON.uid}`, 'error')
100
+ return err
101
+ })
102
+ }
92
103
  },
93
- {
94
- concurrency: vLimit,
95
- },
96
- )
97
- .then(function () {
98
- addlogs(config, 'Batch no ' + (batch + 1) + ' of assets is complete', 'success');
99
- helper.writeFile(assetContentsFile, self.assetContents);
100
- })
101
- .catch(function (error) {
102
- console.log('Error fetch/download the asset', error && error.message);
103
- addlogs(config, 'Asset batch ' + (batch + 1) + ' failed to download', 'error');
104
- addlogs(config, error, 'error');
105
- // log this error onto a file - send over retries
106
- });
104
+ { concurrency: self.vLimit }
105
+ ).then(function () {
106
+ addlogs(self.config, 'Batch no ' + (batch + 1) + ' of assets is complete', 'success');
107
+ // helper.writeFileSync(this.assetContentsFile, self.assetContents)
108
+ }).catch(function (error) {
109
+ console.log('Error fetch/download the asset', (error && error.message))
110
+ addlogs(self.config, 'Asset batch ' + (batch + 1) + ' failed to download', 'error')
111
+ addlogs(self.config, error, 'error')
112
+ })
113
+ }).catch(function (error) {
114
+ addlogs(self.config, error, 'error')
115
+ reject(error)
107
116
  })
108
- .catch(function (error) {
109
- return reject(error);
110
- });
111
- },
112
- {
113
- concurrency: 1,
114
117
  },
115
- )
116
- .then(function () {
117
- return self
118
- .exportFolders()
119
- .then(function () {
120
- addlogs(config, chalk.green('Asset export completed successfully'), 'success');
121
- return resolve();
122
- })
123
- .catch(function (error) {
124
- return reject(error);
125
- });
126
- })
127
- .catch(function (error) {
128
- addlogs(
129
- config,
130
- chalk.red('Asset export failed due to the following errrors ' + JSON.stringify(error), 'error'),
131
- );
132
- return reject(error);
133
- });
118
+ { concurrency: self.assetConfig.concurrencyLimit || 1 }
119
+ ).then(function () {
120
+ helper.writeFileSync(self.assetContentsFile, self.assetContents)
121
+
122
+ return self
123
+ .exportFolders()
124
+ .then(function () {
125
+ addlogs(self.config, chalk.green('Asset export completed successfully'), 'success');
126
+ return resolve();
127
+ })
128
+ .catch(function (error) {
129
+ addlogs(self.config, error, 'success')
130
+ reject(error)
131
+ })
132
+ }).catch(function (error) {
133
+ helper.writeFileSync(self.assetContentsFile, self.assetContents)
134
+ addlogs(
135
+ self.config,
136
+ chalk.red('Asset export failed due to the following errors ' + JSON.stringify(error), 'error'),
137
+ )
138
+ addlogs(self.config, error, 'success')
139
+ reject(error)
140
+ })
141
+ }).catch(function (error) {
142
+ addlogs(self.config, error, 'success')
143
+ reject(error)
134
144
  })
135
- .catch(function (error) {
136
- return reject(error);
137
- });
138
- });
139
- },
140
- exportFolders: function () {
145
+ })
146
+ }
147
+
148
+ exportFolders() {
141
149
  let self = this;
142
150
  return new Promise(function (resolve, reject) {
143
151
  return self
144
152
  .getAssetCount(true)
145
153
  .then(function (fCount) {
146
154
  if (fCount === 0) {
147
- addlogs(config, 'No folders were found in the stack!', 'success');
148
- return resolve();
155
+ addlogs(self.config, 'No folders were found in the stack!', 'success');
156
+ return resolve()
149
157
  }
158
+
150
159
  return self
151
160
  .getFolderJSON(0, fCount)
152
161
  .then(function () {
153
162
  // asset folders have been successfully exported
154
- addlogs(config, 'Asset-folders have been successfully exported!', 'success');
163
+ addlogs(self.config, 'Asset-folders have been successfully exported!', 'success');
155
164
  return resolve();
156
- })
157
- .catch(function (error) {
158
- addlogs(config, chalk.red('Error while exporting asset-folders!'), 'error');
165
+ }).catch(function (error) {
166
+ addlogs(self.config, chalk.red('Error while exporting asset-folders!'), 'error');
159
167
  return reject(error);
160
- });
168
+ })
161
169
  })
162
170
  .catch(function (error) {
163
- addlogs(config, error, 'error');
171
+ addlogs(self.config, error, 'error')
164
172
  // error while fetching asset folder count
165
- return reject(error);
173
+ return reject(error)
166
174
  });
167
175
  });
168
- },
169
- getFolderJSON: function (skip, fCount) {
170
- let self = this;
176
+ }
177
+
178
+ getFolderJSON(skip, fCount) {
179
+ let self = this
171
180
  return new Promise(function (resolve, reject) {
172
181
  if (typeof skip !== 'number') {
173
- skip = 0;
182
+ skip = 0
174
183
  }
184
+
175
185
  if (skip >= fCount) {
176
- helper.writeFile(folderJSONPath, self.folderData);
177
- return resolve();
186
+ helper.writeFileSync(self.folderJSONPath, self.folderData)
187
+ return resolve()
178
188
  }
179
189
 
180
190
  const queryRequestObj = {
191
+ skip,
181
192
  include_folders: true,
182
- query: { is_dir: true },
183
- skip: skip,
184
- };
193
+ query: { is_dir: true }
194
+ }
185
195
 
186
- client
187
- .stack({ api_key: config.source_stack, management_token: config.management_token })
196
+ self.client
197
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
188
198
  .asset()
189
199
  .query(queryRequestObj)
190
200
  .find()
191
201
  .then((response) => {
192
- response.items.forEach(function (folder) {
193
- self.folderData.push(folder);
194
- });
195
- skip += 100;
196
- return self.getFolderJSON(skip, fCount).then(resolve).catch(reject);
197
- });
198
- });
199
- },
200
- getAssetCount: function (folder) {
202
+ skip += 100
203
+ self.folderData.push(...response.items)
204
+ return self.getFolderJSON(skip, fCount).then(resolve).catch(reject)
205
+ })
206
+ })
207
+ }
208
+
209
+ getAssetCount(folder) {
210
+ const self = this
201
211
  return new Promise(function (resolve, reject) {
202
212
  if (folder && typeof folder === 'boolean') {
203
- let queryOptions = { include_folders: true, query: { is_dir: true }, include_count: true };
204
- client
205
- .stack({ api_key: config.source_stack, management_token: config.management_token })
213
+ let queryOptions = {
214
+ skip: 99999990,
215
+ include_count: true,
216
+ include_folders: true,
217
+ query: { is_dir: true }
218
+ }
219
+ self.client
220
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
206
221
  .asset()
207
222
  .query(queryOptions)
208
223
  .find()
@@ -210,77 +225,77 @@ ExportAssets.prototype = {
210
225
  return resolve(asset.count);
211
226
  })
212
227
  .catch((error) => {
213
- addlogs(config, error, 'error');
228
+ addlogs(self.config, error, 'error');
214
229
  });
215
230
  } else {
216
- let queryOptions = { include_count: true };
217
- client
218
- .stack({ api_key: config.source_stack, management_token: config.management_token })
231
+ let queryOptions = { skip: 99999990, include_count: true }
232
+ self.client
233
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
219
234
  .asset()
220
235
  .query(queryOptions)
221
236
  .find()
222
- .then((asset) => {
223
- return resolve(asset.count);
224
- })
237
+ .then(({ count }) => resolve(count))
225
238
  .catch((error) => {
226
- addlogs(config, error, 'error');
227
- return reject();
228
- });
239
+ addlogs(self.config, error, 'error')
240
+ reject(error)
241
+ })
229
242
  }
230
- });
231
- },
232
- getAssetJSON: function (skip) {
243
+ })
244
+ }
245
+
246
+ getAssetJSON(skip) {
247
+ const self = this
233
248
  return new Promise(function (resolve, reject) {
234
249
  if (typeof skip !== 'number') {
235
- skip = 0;
250
+ skip = 0
236
251
  }
237
252
  const queryRequestObj = {
238
253
  skip: skip,
239
- limit: bLimit,
254
+ limit: self.bLimit,
240
255
  include_publish_details: true,
241
256
  except: {
242
- BASE: invalidKeys,
243
- },
244
- };
257
+ BASE: self.invalidKeys
258
+ }
259
+ }
245
260
 
246
- client
247
- .stack({ api_key: config.source_stack, management_token: config.management_token })
261
+ self.client
262
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
248
263
  .asset()
249
264
  .query(queryRequestObj)
250
265
  .find()
251
- .then((assetResponse) => {
252
- return resolve(assetResponse.items);
253
- })
266
+ .then(({ items }) => resolve(items))
254
267
  .catch((error) => {
255
- addlogs(config, error, 'error');
256
- return reject();
257
- });
258
- });
259
- },
260
- getVersionedAssetJSON: function (uid, version, bucket) {
261
- let self = this;
262
- let assetVersionInfo = bucket || [];
268
+ addlogs(self.config, error, 'error')
269
+ return reject()
270
+ })
271
+ })
272
+ }
273
+
274
+ getVersionedAssetJSON(uid, version, bucket) {
275
+ let self = this
276
+ let assetVersionInfo = bucket || []
277
+
263
278
  return new Promise(function (resolve, reject) {
264
279
  if (self.assetDownloadRetry[uid + version] > self.assetDownloadRetryLimit) {
265
- console.log('Reached max', self.assetDownloadRetry[uid + version]);
266
- return reject(new Error('Asset Max download retry limit exceeded! ' + uid));
280
+ console.log('Reached max', self.assetDownloadRetry[uid + version])
281
+ return reject(new Error('Asset Max download retry limit exceeded! ' + uid))
267
282
  }
268
283
 
269
284
  if (version <= 0) {
270
- const assetVersionInfoFile = path.resolve(assetsFolderPath, uid, '_contentstack_' + uid + '.json');
271
- helper.writeFile(assetVersionInfoFile, assetVersionInfo);
272
- return resolve();
285
+ const assetVersionInfoFile = path.resolve(self.assetsFolderPath, uid, '_contentstack_' + uid + '.json');
286
+ helper.writeFileSync(assetVersionInfoFile, assetVersionInfo)
287
+ return resolve()
273
288
  }
274
289
  let queryrequestOption = {
275
290
  version: version,
276
291
  include_publish_details: true,
277
292
  except: {
278
- BASE: invalidKeys,
279
- },
280
- };
293
+ BASE: self.invalidKeys
294
+ }
295
+ }
281
296
 
282
- client
283
- .stack({ api_key: config.source_stack, management_token: config.management_token })
297
+ self.client
298
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
284
299
  .asset(uid)
285
300
  .fetch(queryrequestOption)
286
301
  .then((versionedAssetJSONResponse) => {
@@ -293,126 +308,137 @@ ExportAssets.prototype = {
293
308
  self
294
309
  .getVersionedAssetJSON(uid, --version, assetVersionInfo)
295
310
  .then(resolve)
296
- .catch(reject);
311
+ .catch(reject)
297
312
  })
298
- .catch(reject);
313
+ .catch(reject)
299
314
  })
300
315
  .catch((error) => {
316
+ addlogs(self.config, error, 'error')
301
317
  console.log('Error on fetch', error && error.message);
318
+
302
319
  if (error.status === 408) {
303
320
  console.log('retrying', uid);
304
321
  // retrying when timeout
305
322
  self.assetDownloadRetry[uid + version]
306
323
  ? ++self.assetDownloadRetry[uid + version]
307
324
  : (self.assetDownloadRetry[uid + version] = 1);
308
- return self.getVersionedAssetJSON(uid, version, assetVersionInfo).then(resolve).catch(reject);
325
+ return self.getVersionedAssetJSON(uid, version, assetVersionInfo)
326
+ .then(resolve)
327
+ .catch(reject)
309
328
  }
310
- reject(error);
311
- });
312
- });
313
- },
314
- downloadAsset: function (asset) {
329
+
330
+ reject(error)
331
+ })
332
+ })
333
+ }
334
+
335
+ downloadAsset(asset) {
315
336
  let self = this;
316
337
  return new Promise(async function (resolve, reject) {
317
- const assetFolderPath = path.resolve(assetsFolderPath, asset.uid);
318
- const assetFilePath = path.resolve(assetFolderPath, asset.filename);
338
+ const assetFolderPath = path.resolve(self.assetsFolderPath, asset.uid)
339
+ const assetFilePath = path.resolve(assetFolderPath, asset.filename)
340
+
319
341
  if (fs.existsSync(assetFilePath)) {
320
342
  addlogs(
321
- config,
343
+ self.config,
322
344
  'Skipping download of { title: ' + asset.filename + ', uid: ' + asset.uid + ' }, as they already exist',
323
- 'success',
324
- );
325
- return resolve();
345
+ 'success'
346
+ )
347
+ return resolve()
326
348
  }
327
349
  self.assetStream = {
328
- url: config.securedAssets ? `${asset.url}?authtoken=${config.authtoken || config.auth_token}` : asset.url,
329
- };
350
+ url: self.config.securedAssets ? `${asset.url}?authtoken=${self.config.authtoken || self.config.auth_token}` : asset.url,
351
+ }
330
352
 
331
- helper.makeDirectory(assetFolderPath);
332
- const assetFileStream = fs.createWriteStream(assetFilePath);
333
- self.assetStream.url = encodeURI(self.assetStream.url);
334
- httpClient
353
+ helper.makeDirectory(assetFolderPath)
354
+ const assetFileStream = fs.createWriteStream(assetFilePath)
355
+ self.assetStream.url = encodeURI(self.assetStream.url)
356
+ self.httpClient
335
357
  .options({ responseType: 'stream' })
336
358
  .get(self.assetStream.url)
337
359
  .then(({ data: assetStreamRequest }) => {
338
- if (assetConfig.enableDownloadStatus) {
360
+ if (self.assetConfig.enableDownloadStatus) {
339
361
  const str = progress({
340
362
  time: 5000,
341
363
  length: assetStreamRequest.headers['content-length'],
342
- });
364
+ })
343
365
  str.on('progress', function (progressData) {
344
366
  console.log(`${asset.filename}: ${Math.round(progressData.percentage)}%`);
345
367
  });
346
368
  assetStreamRequest.pipe(str).pipe(assetFileStream);
347
369
  }
348
- assetStreamRequest.pipe(assetFileStream);
370
+ assetStreamRequest.pipe(assetFileStream)
371
+ }).catch((error) => {
372
+ addlogs(self.config, error, 'error')
373
+ reject(error)
349
374
  })
350
- .catch(reject);
351
375
  assetFileStream
352
376
  .on('close', function () {
353
- addlogs(config, 'Downloaded ' + asset.filename + ': ' + asset.uid + ' successfully!', 'success');
377
+ addlogs(self.config, 'Downloaded ' + asset.filename + ': ' + asset.uid + ' successfully!', 'success');
354
378
  return resolve();
355
379
  })
356
- .on('error', reject);
380
+ .on('error', (error) => {
381
+ addlogs(self.config, error, 'error')
382
+ reject(error)
383
+ })
357
384
  });
358
- },
359
- getFolders: function () {
385
+ }
386
+
387
+ getFolders() {
360
388
  let self = this;
361
389
  return new Promise(function (resolve, reject) {
362
390
  return self
363
391
  .getAssetCount(true)
364
392
  .then(function (count) {
365
393
  if (count === 0) {
366
- addlogs(config, 'No folders were found in the stack', 'success');
367
- return resolve();
394
+ addlogs(self.config, 'No folders were found in the stack', 'success')
395
+ return resolve()
368
396
  }
369
397
  return self
370
398
  .getFolderDetails(0, count)
371
399
  .then(function () {
372
- addlogs(config, chalk.green('Exported asset-folders successfully!'), 'success');
373
- return resolve();
400
+ addlogs(self.config, chalk.green('Exported asset-folders successfully!'), 'success')
401
+ return resolve()
402
+ }).catch(function (error) {
403
+ addlogs(self.config, error, 'error')
404
+ reject(error)
374
405
  })
375
- .catch(function (error) {
376
- return reject(error);
377
- });
378
- })
379
- .catch(function (error) {
380
- return reject(error);
406
+ }).catch(function (error) {
407
+ addlogs(self.config, error, 'error')
408
+ reject(error)
381
409
  });
382
410
  });
383
- },
384
- getFolderDetails: function (skip, tCount) {
411
+ }
412
+
413
+ getFolderDetails(skip, tCount) {
385
414
  let self = this;
386
415
  return new Promise(function (resolve, reject) {
387
416
  if (typeof skip !== 'number') {
388
- skip = 0;
417
+ skip = 0
389
418
  }
390
419
  if (skip > tCount) {
391
- helper.writeFile(folderJSONPath, self.folderContents);
392
- return resolve();
420
+ helper.writeFileSync(self.folderJSONPath, self.folderContents)
421
+ return resolve()
393
422
  }
394
423
  let queryRequestObj = {
395
- include_folders: true,
396
- query: { is_dir: true },
397
424
  skip: skip,
398
- };
399
- client
400
- .stack({ api_key: config.source_stack, management_token: config.management_token })
425
+ include_folders: true,
426
+ query: { is_dir: true }
427
+ }
428
+ self.client
429
+ .stack({ api_key: self.config.source_stack, management_token: self.config.management_token })
401
430
  .asset()
402
431
  .query(queryRequestObj)
403
432
  .find()
404
433
  .then((folderDetailsResponse) => {
405
434
  for (let i in folderDetailsResponse.items) {
406
- self.folderContents.push(folderDetailsResponse.items[i]);
435
+ self.folderContents.push(folderDetailsResponse.items[i])
407
436
  }
408
- skip += 100;
409
- return self.getFolderDetails(skip, tCount).then(resolve).catch(reject);
437
+ skip += 100
438
+ return self.getFolderDetails(skip, tCount).then(resolve).catch(reject)
439
+ }).catch((error) => {
440
+ addlogs(self.config, error, 'error')
410
441
  })
411
- .catch((error) => {
412
- addlogs(config, error, 'error');
413
- });
414
- });
415
- },
416
- };
417
-
418
- module.exports = new ExportAssets();
442
+ })
443
+ }
444
+ }