index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. const path = require('path')
  2. const log = require('./util/log')
  3. const report = require('./reports')
  4. const matcher = require('./util/matcher')
  5. const Group = report.Group
  6. const Backup = require('./backup')
  7. const os = require('os')
  8. // Backup source directory
  9. var backupDirectory = path.join(os.homedir(), '/Library/Application Support/MobileSync/Backup/')
  10. // Object containing all report modules
  11. var moduleCache = report.types
  12. // Array of plugin modules
  13. var plugins = []
  14. /**
  15. * Add an array of plugins to the plugins list.
  16. * @param {Array<Object>} array contains array of plugin objects.
  17. */
  18. function registerModule (array) {
  19. if (!(array instanceof Array)) {
  20. array = [ array ]
  21. }
  22. plugins.push(...array)
  23. moduleCache = getCompleteModuleList()
  24. }
  25. /**
  26. * Remove all non-default plugins.
  27. */
  28. function clearModules () {
  29. plugins = []
  30. moduleCache = getCompleteModuleList()
  31. }
  32. /**
  33. * Get all modules in a top-down manner.
  34. */
  35. function getCompleteModuleList () {
  36. let allModules = {}
  37. // Add all of the require()'d modules into the plugins list.
  38. plugins.forEach(function (plugin) {
  39. allModules = { ...allModules, ...plugin }
  40. })
  41. // Add all of the modules to a single object.
  42. // JS's behavior dictates that the items are added sequentially
  43. // So, the default reports overwrite any third party plugin.
  44. let result = {
  45. ...allModules,
  46. ...report.types
  47. }
  48. moduleCache = result
  49. return result
  50. }
  51. /**
  52. * Try to find a single report.
  53. * @param {string} query name to find.
  54. */
  55. function findReport (query) {
  56. return new Promise((resolve, reject) => {
  57. // Check there is no wildcard in the query.
  58. if (query.indexOf('*') > -1) {
  59. return reject(new Error('Cannot run a wildcard match here.'))
  60. }
  61. // Run matches.
  62. let matches = matcher(moduleCache, query, (el) => !(el instanceof Group))
  63. // If no report found, fail.
  64. if (matches.length === 0) {
  65. return reject(new Error(`No report found with name "${query}"`))
  66. }
  67. // If multiple matches, fail.
  68. if (matches.length > 1) {
  69. return reject(new Error(`Multiple report matches for name "${query}", not allowed.`))
  70. }
  71. // Resolve match
  72. resolve(matches[0])
  73. })
  74. }
  75. /**
  76. * Translate the raw output of a report to the correct result, based on the "raw" parameter.
  77. * @param {Object} report The report module
  78. * @param {Object} result Raw data output from the aforementioned report
  79. * @param {Object} params parameters object.
  80. */
  81. function compileReport (report, result, { raw }) {
  82. return new Promise((resolve, reject) => {
  83. if (!raw && report.output) {
  84. if (result instanceof Array) {
  85. log.verbose('compiling report (array)...')
  86. // if it's an array, translate each item.
  87. result = result.map(item => {
  88. // For each item, run the functions on the entry.
  89. let editedResult = {}
  90. for (let [key, value] of Object.entries(report.output)) {
  91. editedResult[key] = value(item)
  92. }
  93. return editedResult
  94. })
  95. resolve(result)
  96. } else {
  97. log.verbose('compiling report (single)...')
  98. // Otherwise, translate the object returned.
  99. let editedResult = {}
  100. for (let [key, value] of Object.entries(report.output)) {
  101. editedResult[key] = value(result)
  102. }
  103. resolve(editedResult)
  104. }
  105. } else {
  106. resolve(result)
  107. }
  108. })
  109. }
  110. /**
  111. * Run a named report and resolve to it's output.
  112. * The output is formatted based on the `report.output` key, if the params.raw option is NOT set to true.
  113. * @param {string} query report name
  114. * @param {Object=} params parameters.
  115. */
  116. function run (query, params) {
  117. params = params || {}
  118. return new Promise(async (resolve, reject) => {
  119. try {
  120. let report = await findReport(query)
  121. let result = await runReport(report, params)
  122. let compiled = await compileReport(report, result, params)
  123. resolve(compiled)
  124. } catch (e) {
  125. reject(e)
  126. }
  127. })
  128. }
  129. /**
  130. * Run a report
  131. * @param {object} report report module
  132. * @param {object=} params parameters
  133. */
  134. function runReport (report, params) {
  135. params = params || {}
  136. return new Promise((resolve, reject) => {
  137. var backup
  138. // Cannot run < v3 backups in this manner.
  139. if (!report.version || report.version < 3) {
  140. return reject(new Error(`Cannot call ${report.name} as a module, it is not updated to the v3 api`))
  141. }
  142. // If it requires a backup and none is provided, reject.
  143. if (report.requiresBackup) {
  144. if (!params.backup) {
  145. return reject(new Error('Please specify the `backup` parameter to run this report.'))
  146. }
  147. backup = new Backup(backupDirectory, params.backup)
  148. }
  149. // Input params to func
  150. let inputParams = {
  151. ...params,
  152. backup
  153. }
  154. report.run(module.exports, inputParams)
  155. .then(resolve)
  156. .catch(reject)
  157. })
  158. }
  159. module.exports = {
  160. // Exported Libraries
  161. Backup,
  162. Group,
  163. // Module management
  164. registerModule,
  165. clearModules,
  166. get modules () {
  167. return moduleCache
  168. },
  169. // Source directory
  170. set base (value) {
  171. backupDirectory = value
  172. },
  173. get base () {
  174. return backupDirectory
  175. },
  176. // Runners
  177. run,
  178. findReport,
  179. runReport,
  180. compileReport,
  181. // misc
  182. setLogLevel (lvl) {
  183. log.setVerbose(lvl)
  184. }
  185. }