create-dmg/cli.js

138 lines
2.8 KiB
JavaScript
Raw Normal View History

2017-03-27 14:09:27 +00:00
#!/usr/bin/env node
'use strict';
const path = require('path');
const fs = require('fs');
const meow = require('meow');
const appdmg = require('appdmg');
const plist = require('plist');
const Ora = require('ora');
const execa = require('execa');
2018-04-29 12:07:51 +00:00
if (process.platform !== 'darwin') {
console.error('macOS only');
process.exit(1);
}
2017-03-27 14:09:27 +00:00
const cli = meow(`
2018-04-29 12:02:41 +00:00
Usage
$ create-dmg <app> [destination]
2018-04-29 12:02:41 +00:00
2018-04-29 13:58:01 +00:00
Options
--overwrite Overwrite existing DMG with the same name
2018-04-29 12:02:41 +00:00
Examples
2017-03-27 14:09:27 +00:00
$ create-dmg 'Lungo.app'
2018-04-29 12:02:41 +00:00
$ create-dmg 'Lungo.app' Build/Releases
2018-04-29 13:58:01 +00:00
`, {
flags: {
overwrite: {
type: 'boolean'
}
}
});
2017-03-27 14:09:27 +00:00
2018-04-29 12:07:51 +00:00
let [appPath, destPath] = cli.input;
2017-03-27 14:09:27 +00:00
2018-04-29 12:07:51 +00:00
if (!appPath) {
2017-03-27 14:09:27 +00:00
console.error('Specify an app');
process.exit(1);
}
2018-04-29 12:07:51 +00:00
if (!destPath) {
destPath = process.cwd();
}
let infoPlist;
try {
infoPlist = fs.readFileSync(path.join(appPath, 'Contents/Info.plist'), 'utf8');
} catch (err) {
if (err.code === 'ENOENT') {
2018-04-29 12:07:51 +00:00
console.error(`Could not find \`${path.relative(process.cwd(), appPath)}\``);
process.exit(1);
}
throw err;
}
const appInfo = plist.parse(infoPlist);
const appName = appInfo.CFBundleDisplayName || appInfo.CFBundleName;
2017-10-23 12:33:07 +00:00
// `const appIconName = appInfo.CFBundleIconFile.replace(/\.icns/, '');
const dmgPath = path.join(destPath, `${appName} ${appInfo.CFBundleShortVersionString}.dmg`);
2017-03-27 14:09:27 +00:00
const ora = new Ora('Creating DMG');
ora.start();
2018-04-29 13:58:01 +00:00
if (cli.flags.overwrite) {
try {
fs.unlinkSync(dmgPath);
} catch (_) {}
}
2017-03-27 14:09:27 +00:00
const ee = appdmg({
target: dmgPath,
basepath: __dirname,
specification: {
title: appName,
2017-10-23 12:31:51 +00:00
// Disabled because of #16
// icon: path.join(appPath, 'Contents/Resources', `${appIconName}.icns`),
//
2017-03-27 14:09:27 +00:00
// Use transparent background and `background-color` option when this is fixed:
// https://github.com/LinusU/node-appdmg/issues/135
background: path.join(__dirname, 'assets/dmg-background.png'),
'icon-size': 160,
format: 'ULFO',
window: {
size: {
width: 660,
height: 400
}
},
contents: [
{
x: 180,
y: 170,
type: 'file',
path: appPath
},
{
x: 480,
y: 170,
type: 'link',
path: '/Applications'
}
]
}
});
ee.on('progress', info => {
if (info.type === 'step-begin') {
ora.text = info.title;
}
});
2018-04-29 12:07:51 +00:00
ee.on('finish', async () => {
2017-03-27 14:09:27 +00:00
ora.text = 'Code signing DMG';
2018-04-29 12:07:51 +00:00
try {
await execa('codesign', ['--sign', 'Developer ID Application', dmgPath]);
const {stderr} = await execa('codesign', [dmgPath, '--display', '--verbose=2']);
2017-03-27 14:09:27 +00:00
2018-04-29 12:07:51 +00:00
const match = /^Authority=(.*)$/m.exec(stderr);
2017-03-27 14:09:27 +00:00
if (!match) {
ora.fail('Not code signed');
process.exit(1);
}
ora.info(`Code signing identity: ${match[1]}`).start();
ora.succeed('DMG created');
2018-04-29 12:07:51 +00:00
} catch (err) {
ora.fail(`Code signing failed. The DMG is fine, just not code signed.\n${err.stderr.trim()}`);
process.exit(1);
2018-04-29 12:07:51 +00:00
}
2017-03-27 14:09:27 +00:00
});
2018-04-29 12:07:51 +00:00
ee.on('error', error => {
ora.fail(error);
2017-03-27 14:09:27 +00:00
process.exit(1);
});