From cf83b9165b9fa920f6004427d9d7694a133a5b29 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 11 May 2017 19:55:43 -0700 Subject: [PATCH 1/3] Infer win32metadata from package.json/top-level options Closes #297. Fixes #611. --- docs/api.md | 12 +++--- index.js | 2 +- infer.js | 27 ++++++++++++- package.json | 1 + .../fixtures/infer-win32metadata/package.json | 9 +++++ test/infer.js | 38 ++++++++++++++++++- test/win32.js | 12 ++++++ usage.txt | 10 ++--- win32.js | 10 +++-- 9 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 test/fixtures/infer-win32metadata/package.json diff --git a/docs/api.md b/docs/api.md index 0591a577..05f32dd4 100644 --- a/docs/api.md +++ b/docs/api.md @@ -373,15 +373,15 @@ option. Maps to the `CFBundleURLName` metadata property. *Object* Object (also known as a "hash") of application metadata to embed into the executable: -- `CompanyName` -- `FileDescription` -- `OriginalFilename` -- `ProductName` -- `InternalName` +- `CompanyName` (defaults to `author` name from the nearest `package.json`) +- `FileDescription` (defaults to `description` from the nearest `package.json`) +- `OriginalFilename` (defaults to renamed `.exe` file) +- `ProductName` (defaults to either `productName` or `name` from the nearest `package.json`) +- `InternalName` (defaults to either `productName` or `name` from the nearest `package.json`) - `requested-execution-level` - `application-manifest` -For more information, see the [node-rcedit module](https://github.com/electron/node-rcedit). +For more information, see the [`node-rcedit` module](https://github.com/electron/node-rcedit). ## callback diff --git a/index.js b/index.js index 44d043c5..018022bf 100644 --- a/index.js +++ b/index.js @@ -150,7 +150,7 @@ module.exports = pify(function packager (opts, cb) { common.camelCase(opts, true) - getMetadataFromPackageJSON(opts, path.resolve(process.cwd(), opts.dir) || process.cwd(), function (err) { + getMetadataFromPackageJSON(platforms, opts, path.resolve(process.cwd(), opts.dir) || process.cwd(), function (err) { if (err) return cb(err) if (/ Helper$/.test(opts.name)) { diff --git a/infer.js b/infer.js index d081ab19..83f75205 100644 --- a/infer.js +++ b/infer.js @@ -2,6 +2,7 @@ const debug = require('debug')('electron-packager') const getPackageInfo = require('get-package-info') +const parseAuthor = require('parse-author') const path = require('path') const resolve = require('resolve') @@ -61,7 +62,7 @@ function getVersion (opts, electronProp, cb) { } } -module.exports = function getMetadataFromPackageJSON (opts, dir, cb) { +module.exports = function getMetadataFromPackageJSON (platforms, opts, dir, cb) { let props = [] if (!opts.name) props.push(['productName', 'name']) if (!opts.appVersion) props.push('version') @@ -76,6 +77,16 @@ module.exports = function getMetadataFromPackageJSON (opts, dir, cb) { ]) } + if (platforms.indexOf('win32') !== -1) { + if (!(opts.win32metadata && opts.win32metadata.FileDescription)) { + props.push('description') + } + + if (!(opts.win32metadata && opts.win32metadata.CompanyName)) { + props.push('author') + } + } + // Name and version provided, no need to infer if (props.length === 0) return cb(null) @@ -110,6 +121,20 @@ module.exports = function getMetadataFromPackageJSON (opts, dir, cb) { opts.appVersion = result.values.version } + if ((result.values.description || result.values.author) && !opts.win32metadata) { + opts.win32metadata = {} + } + + if (result.values.description) { + debug(`Inferring win32metadata.FileDescription from description in ${result.source.description.src}`) + opts.win32metadata.FileDescription = result.values.description + } + + if (result.values.author) { + debug(`Inferring win32metadata.CompanyName from description in ${result.source.author.src}`) + opts.win32metadata.CompanyName = parseAuthor(result.values.author).name + } + if (result.values['dependencies.electron']) { return getVersion(opts, result.source['dependencies.electron'], cb) } else { diff --git a/package.json b/package.json index 894b9d7d..28c4e208 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "fs-extra": "^3.0.0", "get-package-info": "^1.0.0", "minimist": "^1.1.1", + "parse-author": "^2.0.0", "pify": "^3.0.0", "plist": "^2.0.0", "rcedit": "^0.9.0", diff --git a/test/fixtures/infer-win32metadata/package.json b/test/fixtures/infer-win32metadata/package.json new file mode 100644 index 00000000..088779de --- /dev/null +++ b/test/fixtures/infer-win32metadata/package.json @@ -0,0 +1,9 @@ +{ + "main": "main.js", + "productName": "MainJS", + "author": "Foo Bar ", + "description": "Some description", + "devDependencies": { + "electron-prebuilt-compile": "1.4.15" + } +} diff --git a/test/infer.js b/test/infer.js index f58ceeab..2c133b9c 100644 --- a/test/infer.js +++ b/test/infer.js @@ -19,7 +19,7 @@ function createInferElectronVersionTest (fixture, packageName) { delete opts.electronVersion opts.dir = path.join(__dirname, 'fixtures', fixture) - pify(getMetadataFromPackageJSON)(opts, opts.dir) + pify(getMetadataFromPackageJSON)([], opts, opts.dir) .then((pkg) => { const packageJSON = require(path.join(opts.dir, 'package.json')) t.equal(opts.electronVersion, packageJSON.devDependencies[packageName], `The version should be inferred from installed ${packageName} version`) @@ -71,7 +71,7 @@ function createInferMissingVersionTest (opts) { delete opts.electronVersion opts.dir = dir - return pify(getMetadataFromPackageJSON)(opts, dir) + return pify(getMetadataFromPackageJSON)([], opts, dir) }).then(() => { const packageJSON = require(path.join(opts.dir, 'package.json')) t.equal(opts.electronVersion, packageJSON.devDependencies['electron'], 'The version should be inferred from installed electron module version') @@ -80,6 +80,19 @@ function createInferMissingVersionTest (opts) { } } +function testInferWin32metadata (t, opts, expected, assertionMessage) { + t.timeoutAfter(config.timeout) + copyFixtureToTempDir('infer-win32metadata') + .then((dir) => { + opts.dir = dir + + return pify(getMetadataFromPackageJSON)(['win32'], opts, dir) + }).then(() => { + t.deepEqual(opts.win32metadata, expected, assertionMessage) + return t.end() + }).catch(t.end) +} + function createInferMissingFieldsTest (opts) { return createInferFailureTest(opts, 'infer-missing-fields') } @@ -100,6 +113,27 @@ util.testSinglePlatform('infer using `electron-prebuilt` package', createInferEl util.testSinglePlatform('infer using `electron-prebuilt-compile` package', createInferElectronVersionTest('infer-electron-prebuilt-compile', 'electron-prebuilt-compile')) util.testSinglePlatform('infer using `electron` package only', createInferMissingVersionTest) util.testSinglePlatform('infer where `electron` version is preferred over `electron-prebuilt`', createInferElectronVersionTest('basic-renamed-to-electron', 'electron')) +util.testSinglePlatform('infer win32metadata', (opts) => { + return (t) => { + const expected = { + CompanyName: 'Foo Bar', + FileDescription: 'Some description' + } + + testInferWin32metadata(t, opts, expected, 'win32metadata matches package.json values') + } +}) +util.testSinglePlatform('do not infer win32metadata if it already exists', (opts) => { + return (t) => { + opts.win32metadata = { + CompanyName: 'Existing', + FileDescription: 'Existing description' + } + const expected = Object.assign({}, opts.win32metadata) + + testInferWin32metadata(t, opts, expected, 'win32metadata did not update with package.json values') + } +}) util.testSinglePlatform('infer missing fields test', createInferMissingFieldsTest) util.testSinglePlatform('infer with bad fields test', createInferWithBadFieldsTest) util.testSinglePlatform('infer with malformed JSON test', createInferWithMalformedJSONTest) diff --git a/test/win32.js b/test/win32.js index 9f8697d4..3341ba15 100644 --- a/test/win32.js +++ b/test/win32.js @@ -163,6 +163,18 @@ test('error message unchanged when error not about wine', (t) => { t.end() }) +test('win32metadata defaults', (t) => { + const opts = { + name: 'Win32 App' + } + const rcOpts = win32.generateRceditOptionsSansIcon(opts, 'Win32 App.exe') + + t.equal(rcOpts['version-string'].InternalName, opts.name) + t.equal(rcOpts['version-string'].OriginalFilename, 'Win32 App.exe') + t.equal(rcOpts['version-string'].ProductName, opts.name) + t.end() +}) + util.packagerTest('win32 executable name is based on sanitized app name', (t) => { const opts = Object.assign({}, baseOpts, {name: '@username/package-name'}) diff --git a/usage.txt b/usage.txt index 7f1107d9..c477fcf8 100644 --- a/usage.txt +++ b/usage.txt @@ -88,10 +88,10 @@ win32metadata a list of sub-properties used to set the application metadata e.g. --win32metadata.CompanyName="Company Inc." or --win32metadata.ProductName="Product" Properties supported: - - CompanyName - - FileDescription - - OriginalFilename - - ProductName - - InternalName + - CompanyName (default: author name from nearest package.json) + - FileDescription (default: description from nearest package.json) + - OriginalFilename (default: renamed exe) + - ProductName (default: appname) + - InternalName (default: appname) - requested-execution-level (user, asInvoker, or requireAdministrator) - application-manifest diff --git a/win32.js b/win32.js index 64310728..33da648e 100644 --- a/win32.js +++ b/win32.js @@ -5,8 +5,12 @@ const debug = require('debug')('electron-packager') const path = require('path') const series = require('run-series') -function generateRceditOptionsSansIcon (opts) { - const win32metadata = Object.assign({}, opts['version-string'], opts.win32metadata) +function generateRceditOptionsSansIcon (opts, newExeName) { + const win32metadata = Object.assign({ + InternalName: opts.name, + OriginalFilename: newExeName, + ProductName: opts.name + }, opts['version-string'], opts.win32metadata) let rcOpts = {'version-string': win32metadata} @@ -56,7 +60,7 @@ module.exports = { } ] - const rcOpts = generateRceditOptionsSansIcon(opts) + const rcOpts = generateRceditOptionsSansIcon(opts, newExeName) if (opts.icon || opts.win32metadata || opts['version-string'] || opts.appCopyright || opts.appVersion || opts.buildVersion) { operations.push(function (cb) { From 12a2d03eb45cf1c14de4d737573bc4b646b9c0cc Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Mon, 5 Jun 2017 23:59:44 -0700 Subject: [PATCH 2/3] Add NEWS entries for win32metadata defaults --- NEWS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.md b/NEWS.md index 2a4c40a1..77e18137 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,12 @@ * Promise support for `packager` - function returns a Promise instead of the return value of the callback (#658) +* `win32metadata.CompanyName` defaults to `author` name from nearest `package.json` (#667) +* `win32metadata.FileDescription` defaults to `description` from nearest `package.json` (#667) +* `win32metadata.OriginalFilename` defaults to renamed `.exe` (#667) +* `win32metadata.ProductName` defaults to `productName` or `name` from nearest `package.json` (#667) +* `win32metadata.InternalName` defaults to `productName` or `name` from + nearest `package.json` (#667) ### Removed From dbe5cb4c5eafe62324e5501b37952e6e34073fc5 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 6 Jun 2017 00:30:00 -0700 Subject: [PATCH 3/3] Default FileDescription to opts.name, not package description Per comments in #667. --- NEWS.md | 3 ++- docs/api.md | 2 +- infer.js | 19 ++++--------------- test/infer.js | 10 ++-------- test/win32.js | 19 +++++++++++++------ usage.txt | 2 +- win32.js | 1 + 7 files changed, 24 insertions(+), 32 deletions(-) diff --git a/NEWS.md b/NEWS.md index 77e18137..a180d69c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,7 +7,8 @@ * Promise support for `packager` - function returns a Promise instead of the return value of the callback (#658) * `win32metadata.CompanyName` defaults to `author` name from nearest `package.json` (#667) -* `win32metadata.FileDescription` defaults to `description` from nearest `package.json` (#667) +* `win32metadata.FileDescription` defaults to `productName` or `name` from + nearest `package.json` (#667) * `win32metadata.OriginalFilename` defaults to renamed `.exe` (#667) * `win32metadata.ProductName` defaults to `productName` or `name` from nearest `package.json` (#667) * `win32metadata.InternalName` defaults to `productName` or `name` from diff --git a/docs/api.md b/docs/api.md index 05f32dd4..74eb687e 100644 --- a/docs/api.md +++ b/docs/api.md @@ -374,7 +374,7 @@ option. Maps to the `CFBundleURLName` metadata property. Object (also known as a "hash") of application metadata to embed into the executable: - `CompanyName` (defaults to `author` name from the nearest `package.json`) -- `FileDescription` (defaults to `description` from the nearest `package.json`) +- `FileDescription` (defaults to either `productName` or `name` from the nearest `package.json`) - `OriginalFilename` (defaults to renamed `.exe` file) - `ProductName` (defaults to either `productName` or `name` from the nearest `package.json`) - `InternalName` (defaults to either `productName` or `name` from the nearest `package.json`) diff --git a/infer.js b/infer.js index 83f75205..f7545e34 100644 --- a/infer.js +++ b/infer.js @@ -77,14 +77,8 @@ module.exports = function getMetadataFromPackageJSON (platforms, opts, dir, cb) ]) } - if (platforms.indexOf('win32') !== -1) { - if (!(opts.win32metadata && opts.win32metadata.FileDescription)) { - props.push('description') - } - - if (!(opts.win32metadata && opts.win32metadata.CompanyName)) { - props.push('author') - } + if (platforms.indexOf('win32') !== -1 && !(opts.win32metadata && opts.win32metadata.CompanyName)) { + props.push('author') } // Name and version provided, no need to infer @@ -121,17 +115,12 @@ module.exports = function getMetadataFromPackageJSON (platforms, opts, dir, cb) opts.appVersion = result.values.version } - if ((result.values.description || result.values.author) && !opts.win32metadata) { + if (result.values.author && !opts.win32metadata) { opts.win32metadata = {} } - if (result.values.description) { - debug(`Inferring win32metadata.FileDescription from description in ${result.source.description.src}`) - opts.win32metadata.FileDescription = result.values.description - } - if (result.values.author) { - debug(`Inferring win32metadata.CompanyName from description in ${result.source.author.src}`) + debug(`Inferring win32metadata.CompanyName from author in ${result.source.author.src}`) opts.win32metadata.CompanyName = parseAuthor(result.values.author).name } diff --git a/test/infer.js b/test/infer.js index 2c133b9c..6d4266e0 100644 --- a/test/infer.js +++ b/test/infer.js @@ -115,20 +115,14 @@ util.testSinglePlatform('infer using `electron` package only', createInferMissin util.testSinglePlatform('infer where `electron` version is preferred over `electron-prebuilt`', createInferElectronVersionTest('basic-renamed-to-electron', 'electron')) util.testSinglePlatform('infer win32metadata', (opts) => { return (t) => { - const expected = { - CompanyName: 'Foo Bar', - FileDescription: 'Some description' - } + const expected = {CompanyName: 'Foo Bar'} testInferWin32metadata(t, opts, expected, 'win32metadata matches package.json values') } }) util.testSinglePlatform('do not infer win32metadata if it already exists', (opts) => { return (t) => { - opts.win32metadata = { - CompanyName: 'Existing', - FileDescription: 'Existing description' - } + opts.win32metadata = {CompanyName: 'Existing'} const expected = Object.assign({}, opts.win32metadata) testInferWin32metadata(t, opts, expected, 'win32metadata did not update with package.json values') diff --git a/test/win32.js b/test/win32.js index 3341ba15..64b51a39 100644 --- a/test/win32.js +++ b/test/win32.js @@ -27,9 +27,15 @@ function generateVersionStringTest (metadataProperties, extraOpts, expectedValue expectedValues = [].concat(expectedValues) assertionMsgs = [].concat(assertionMsgs) metadataProperties.forEach((property, i) => { - var value = expectedValues[i] - var msg = assertionMsgs[i] - t.deepEqual(rcOpts[property], value, msg) + const value = expectedValues[i] + const msg = assertionMsgs[i] + if (property === 'version-string') { + for (const subkey in value) { + t.equal(rcOpts[property][subkey], value[subkey], `${msg} (${subkey})`) + } + } else { + t.equal(rcOpts[property], value, msg) + } }) t.end() } @@ -169,9 +175,10 @@ test('win32metadata defaults', (t) => { } const rcOpts = win32.generateRceditOptionsSansIcon(opts, 'Win32 App.exe') - t.equal(rcOpts['version-string'].InternalName, opts.name) - t.equal(rcOpts['version-string'].OriginalFilename, 'Win32 App.exe') - t.equal(rcOpts['version-string'].ProductName, opts.name) + t.equal(rcOpts['version-string'].FileDescription, opts.name, 'default FileDescription') + t.equal(rcOpts['version-string'].InternalName, opts.name, 'default InternalName') + t.equal(rcOpts['version-string'].OriginalFilename, 'Win32 App.exe', 'default OriginalFilename') + t.equal(rcOpts['version-string'].ProductName, opts.name, 'default ProductName') t.end() }) diff --git a/usage.txt b/usage.txt index c477fcf8..c20befcc 100644 --- a/usage.txt +++ b/usage.txt @@ -89,7 +89,7 @@ win32metadata a list of sub-properties used to set the application metadata or --win32metadata.ProductName="Product" Properties supported: - CompanyName (default: author name from nearest package.json) - - FileDescription (default: description from nearest package.json) + - FileDescription (default: appname) - OriginalFilename (default: renamed exe) - ProductName (default: appname) - InternalName (default: appname) diff --git a/win32.js b/win32.js index 33da648e..d6e6c5de 100644 --- a/win32.js +++ b/win32.js @@ -7,6 +7,7 @@ const series = require('run-series') function generateRceditOptionsSansIcon (opts, newExeName) { const win32metadata = Object.assign({ + FileDescription: opts.name, InternalName: opts.name, OriginalFilename: newExeName, ProductName: opts.name