index.js 5.4 KB

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