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');
|
|
|
|
|
|
|
|
const cli = meow(`
|
2018-04-29 11:57:59 +00:00
|
|
|
Usage:
|
|
|
|
$ create-dmg <app> [destination]
|
|
|
|
|
|
|
|
Examples:
|
2017-03-27 14:09:27 +00:00
|
|
|
$ create-dmg 'Lungo.app'
|
2018-04-29 11:57:59 +00:00
|
|
|
$ create-dmg 'Lungo.app' Build/Releases/
|
2017-03-27 14:09:27 +00:00
|
|
|
`);
|
|
|
|
|
|
|
|
if (process.platform !== 'darwin') {
|
|
|
|
console.error('macOS only');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cli.input.length === 0) {
|
|
|
|
console.error('Specify an app');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const appPath = path.resolve(cli.input[0]);
|
2017-03-31 02:04:34 +00:00
|
|
|
|
2018-04-29 11:57:59 +00:00
|
|
|
let destPath = '.';
|
|
|
|
if (cli.input.length > 1) {
|
|
|
|
destPath = path.resolve(cli.input[1]);
|
|
|
|
}
|
|
|
|
|
2017-03-31 02:04:34 +00:00
|
|
|
let infoPlist;
|
|
|
|
try {
|
|
|
|
infoPlist = fs.readFileSync(path.join(appPath, 'Contents/Info.plist'), 'utf8');
|
|
|
|
} catch (err) {
|
|
|
|
if (err.code === 'ENOENT') {
|
|
|
|
console.error(`Could not find "${path.relative(process.cwd(), appPath)}"`);
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
|
|
|
const appInfo = plist.parse(infoPlist);
|
2017-03-27 14:09:27 +00:00
|
|
|
const appName = appInfo.CFBundleName;
|
2017-10-23 12:33:07 +00:00
|
|
|
// `const appIconName = appInfo.CFBundleIconFile.replace(/\.icns/, '');
|
2017-03-27 19:17:28 +00:00
|
|
|
const dmgPath = `${appName.replace(/ /g, '-')}-${appInfo.CFBundleShortVersionString}.dmg`;
|
2017-03-27 14:09:27 +00:00
|
|
|
|
|
|
|
const ora = new Ora('Creating DMG');
|
|
|
|
ora.start();
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
ee.on('finish', () => {
|
|
|
|
ora.text = 'Code signing DMG';
|
|
|
|
|
|
|
|
execa('codesign', ['--sign', 'Developer ID Application', dmgPath]).then(() => {
|
|
|
|
return execa.stderr('codesign', [dmgPath, '--display', '--verbose=2']);
|
|
|
|
}).then(stderr => {
|
|
|
|
const match = /^Authority=(.*)$/m.exec(stderr);
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
ora.fail('Not code signed');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ora.info(`Code signing identity: ${match[1]}`).start();
|
|
|
|
ora.succeed('DMG created');
|
2017-03-29 06:45:45 +00:00
|
|
|
}).catch(err => {
|
|
|
|
ora.fail(`Code signing failed. The DMG is fine, just not code signed.\n${err.stderr.trim()}`);
|
|
|
|
process.exit(1);
|
|
|
|
});
|
2017-03-27 14:09:27 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
ee.on('error', err => {
|
|
|
|
ora.fail(err);
|
|
|
|
process.exit(1);
|
|
|
|
});
|