flat.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * @module flat
  3. */
  4. 'use strict'
  5. const path = require('path')
  6. const Promise = require('bluebird')
  7. const pkg = require('./package.json')
  8. const util = require('./util')
  9. const debuglog = util.debuglog
  10. const debugwarn = util.debugwarn
  11. const execFileAsync = util.execFileAsync
  12. const validateOptsAppAsync = util.validateOptsAppAsync
  13. const validateOptsPlatformAsync = util.validateOptsPlatformAsync
  14. const Identity = require('./util-identities').findIdentitiesAsync
  15. const findIdentitiesAsync = require('./util-identities').findIdentitiesAsync
  16. /**
  17. * This function returns a promise validating all options passed in opts.
  18. * @function
  19. * @param {Object} opts - Options.
  20. * @returns {Promise} Promise.
  21. */
  22. function validateFlatOptsAsync (opts) {
  23. if (opts.pkg) {
  24. if (typeof opts.pkg !== 'string') return Promise.reject(new Error('`pkg` must be a string.'))
  25. if (path.extname(opts.pkg) !== '.pkg') return Promise.reject(new Error('Extension of output package must be `.pkg`.'))
  26. } else {
  27. debugwarn('No `pkg` passed in arguments, will fallback to default inferred from the given application.')
  28. opts.pkg = path.join(path.dirname(opts.app), path.basename(opts.app, '.app') + '.pkg')
  29. }
  30. if (opts.install) {
  31. if (typeof opts.install !== 'string') return Promise.reject(new Error('`install` must be a string.'))
  32. } else {
  33. debugwarn('No `install` passed in arguments, will fallback to default `/Applications`.')
  34. opts.install = '/Applications'
  35. }
  36. return Promise.map([
  37. validateOptsAppAsync,
  38. validateOptsPlatformAsync
  39. ], function (validate) {
  40. return validate(opts)
  41. })
  42. }
  43. /**
  44. * This function returns a promise flattening the application.
  45. * @function
  46. * @param {Object} opts - Options.
  47. * @returns {Promise} Promise.
  48. */
  49. function flatApplicationAsync (opts) {
  50. var args = [
  51. '--component', opts.app, opts.install,
  52. '--sign', opts.identity.name,
  53. opts.pkg
  54. ]
  55. if (opts.keychain) {
  56. args.unshift('--keychain', opts.keychain)
  57. }
  58. if (opts.scripts) {
  59. args.unshift('--scripts', opts.scripts)
  60. }
  61. debuglog('Flattening... ' + opts.app)
  62. return execFileAsync('productbuild', args)
  63. .thenReturn(undefined)
  64. }
  65. /**
  66. * This function is exported and returns a promise flattening the application.
  67. * @function
  68. * @param {Object} opts - Options.
  69. * @returns {Promise} Promise.
  70. */
  71. var flatAsync = module.exports.flatAsync = function (opts) {
  72. debuglog('electron-osx-sign@%s', pkg.version)
  73. return validateFlatOptsAsync(opts)
  74. .then(function () {
  75. var promise
  76. if (opts.identity) {
  77. debuglog('`identity` passed in arguments.')
  78. if (opts['identity-validation'] === false || opts.identity instanceof Identity) {
  79. return Promise.resolve()
  80. }
  81. promise = findIdentitiesAsync(opts, opts.identity)
  82. } else {
  83. debugwarn('No `identity` passed in arguments...')
  84. if (opts.platform === 'mas') {
  85. debuglog('Finding `3rd Party Mac Developer Installer` certificate for flattening app distribution in the Mac App Store...')
  86. promise = findIdentitiesAsync(opts, '3rd Party Mac Developer Installer:')
  87. } else {
  88. debuglog('Finding `Developer ID Application` certificate for distribution outside the Mac App Store...')
  89. promise = findIdentitiesAsync(opts, 'Developer ID Installer:')
  90. }
  91. }
  92. return promise
  93. .then(function (identities) {
  94. if (identities.length > 0) {
  95. // Provisioning profile(s) found
  96. if (identities.length > 1) {
  97. debugwarn('Multiple identities found, will use the first discovered.')
  98. } else {
  99. debuglog('Found 1 identity.')
  100. }
  101. opts.identity = identities[0]
  102. } else {
  103. // No identity found
  104. return Promise.reject(new Error('No identity found for signing.'))
  105. }
  106. })
  107. })
  108. .then(function () {
  109. // Pre-flat operations
  110. })
  111. .then(function () {
  112. debuglog('Flattening application...', '\n',
  113. '> Application:', opts.app, '\n',
  114. '> Package output:', opts.pkg, '\n',
  115. '> Install path:', opts.install, '\n',
  116. '> Identity:', opts.identity, '\n',
  117. '> Scripts:', opts.scripts)
  118. return flatApplicationAsync(opts)
  119. })
  120. .then(function () {
  121. // Post-flat operations
  122. debuglog('Application flattened.')
  123. })
  124. }
  125. /**
  126. * This function is exported with normal callback implementation.
  127. * @function
  128. * @param {Object} opts - Options.
  129. * @param {RequestCallback} cb - Callback.
  130. */
  131. module.exports.flat = function (opts, cb) {
  132. flatAsync(opts)
  133. .then(function () {
  134. debuglog('Application flattened, saved to: ' + opts.app)
  135. if (cb) cb()
  136. })
  137. .catch(function (err) {
  138. debuglog('Flat failed:')
  139. if (err.message) debuglog(err.message)
  140. else if (err.stack) debuglog(err.stack)
  141. else debuglog(err)
  142. if (cb) cb(err)
  143. })
  144. }