diff --git a/README.md b/README.md
index 0f55ef3..9059515 100644
--- a/README.md
+++ b/README.md
@@ -162,5 +162,5 @@ function handleSquirrelEvent() {
You can get debug messages from this package by running with the environment variable `DEBUG=electron-windows-installer:main` e.g.
```
-DEBUG=electron-windows-installer:main node tasks/electron-winstaller.js
+DEBUG=electron-windows-installer node tasks/electron-winstaller.js
```
diff --git a/package.json b/package.json
index b508a5c..6e925e5 100644
--- a/package.json
+++ b/package.json
@@ -16,23 +16,23 @@
"tdd": "ava --watch"
},
"dependencies": {
- "asar": "~0.10.0",
- "bluebird": "^3.3.4",
+ "archiver": "^1.0.0",
+ "asar": "~0.11.0",
+ "bluebird": "^3.3.5",
"debug": "^2.2.0",
- "fs-extra": "^0.26.7",
- "lodash.template": "^4.2.2",
- "temp": "^0.8.3"
+ "fs-extra": "^0.28.0"
},
"devDependencies": {
- "ava": "^0.13.0",
- "babel-cli": "^6.6.5",
+ "ava": "^0.14.0",
+ "babel-cli": "^6.7.5",
"babel-eslint": "^6.0.2",
"babel-plugin-transform-async-to-module-method": "^6.7.0",
- "babel-plugin-transform-runtime": "^6.6.0",
- "babel-preset-es2015-node4": "^2.0.3",
+ "babel-plugin-transform-runtime": "^6.7.5",
+ "babel-preset-es2015-node4": "^2.1.0",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.7.2",
- "eslint": "^2.4.0"
+ "eslint": "^2.8.0",
+ "temp": "^0.8.3"
},
"engines": {
"node": ">=0.4.0"
diff --git a/spec/installer-spec.js b/spec/installer-spec.js
index c818a8c..5a4aee5 100644
--- a/spec/installer-spec.js
+++ b/spec/installer-spec.js
@@ -1,7 +1,13 @@
import test from 'ava';
import path from 'path';
-import { createTempDir, fileExists, unlink, readDir } from '../src/fs-utils';
+import { fileExists, unlink, readDir } from '../src/fs-utils';
import { createWindowsInstaller } from '../src/index.js';
+import { Promise } from 'bluebird';
+import temp from 'temp';
+
+temp.track();
+
+const createTempDir = Promise.promisify(temp.mkdir);
const log = require('debug')('electron-windows-installer:spec');
diff --git a/src/fs-utils.js b/src/fs-utils.js
index 7dbf93a..b3806e1 100644
--- a/src/fs-utils.js
+++ b/src/fs-utils.js
@@ -1,19 +1,15 @@
-import { copy as extraCopy } from 'fs-extra';
import { Promise } from 'bluebird';
-import temp from 'temp';
-import fs from 'fs';
+import * as fs from 'fs-extra';
const log = require('debug')('electron-windows-installer:fs-utils');
-temp.track();
-
-export const copy = Promise.promisify(extraCopy);
-export const createTempDir = Promise.promisify(temp.mkdir);
+export const copy = Promise.promisify(fs.copy);
export const readFile = Promise.promisify(fs.readFile);
export const readDir = Promise.promisify(fs.readdir);
export const unlink = Promise.promisify(fs.unlink);
-export const writeFile = Promise.promisify(fs.writeFile);
export const rename = Promise.promisify(fs.rename);
+export const mkdirs = Promise.promisify(fs.mkdirs);
+export const remove = Promise.promisify(fs.remove);
const inspect = Promise.promisify(fs.stat);
export async function fileExists(file) {
diff --git a/src/index.js b/src/index.js
index ba6ba7f..2011a39 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,10 +1,12 @@
-import template from 'lodash.template';
import spawn from './spawn-promise';
import asar from 'asar';
import path from 'path';
import * as fsUtils from './fs-utils';
+import archiver from 'archiver';
+import * as fs from 'fs-extra';
+import { Promise } from 'bluebird';
-const log = require('debug')('electron-windows-installer:main');
+const log = require('debug')('electron-windows-installer');
export function convertVersion(version) {
const parts = version.split('-');
@@ -18,29 +20,13 @@ export function convertVersion(version) {
}
export async function createWindowsInstaller(options) {
- let useMono = false;
-
- const monoExe = 'mono';
- const wineExe = 'wine';
-
- if (process.platform !== 'win32') {
- useMono = true;
- if (!wineExe || !monoExe) {
- throw new Error('You must install both Mono and Wine on non-Windows');
- }
-
- log(`Using Mono: '${monoExe}'`);
- log(`Using Wine: '${wineExe}'`);
- }
-
- let { appDirectory, outputDirectory, loadingGif } = options;
- outputDirectory = path.resolve(outputDirectory || 'installer');
+ const useMono = process.platform !== 'win32';
+ const { appDirectory } = options;
const vendorPath = path.join(__dirname, '..', 'vendor');
- const vendorUpdate = path.join(vendorPath, 'Update.exe');
const appUpdate = path.join(appDirectory, 'Update.exe');
- await fsUtils.copy(vendorUpdate, appUpdate);
+ await fsUtils.copy(path.join(vendorPath, 'Update.exe'), appUpdate);
if (options.setupIcon && (options.skipUpdateIcon !== true)) {
let cmd = path.join(vendorPath, 'rcedit.exe');
let args = [
@@ -50,17 +36,12 @@ export async function createWindowsInstaller(options) {
if (useMono) {
args.unshift(cmd);
- cmd = wineExe;
+ cmd = 'wine';
}
await spawn(cmd, args);
}
- const defaultLoadingGif = path.join(__dirname, '..', 'resources', 'install-spinner.gif');
- loadingGif = loadingGif ? path.resolve(loadingGif) : defaultLoadingGif;
-
- let {certificateFile, certificatePassword, remoteReleases, signWithParams, remoteToken} = options;
-
const metadata = {
description: '',
iconUrl: 'https://raw.githubusercontent.com/atom/electron/master/atom/browser/resources/win/atom.ico'
@@ -93,69 +74,139 @@ export async function createWindowsInstaller(options) {
}
}
- metadata.owners = metadata.owners || metadata.authors;
- metadata.version = convertVersion(metadata.version);
- metadata.copyright = metadata.copyright ||
- `Copyright © ${new Date().getFullYear()} ${metadata.authors || metadata.owners}`;
-
- let templateData = await fsUtils.readFile(path.join(__dirname, '..', 'template.nuspec'), 'utf8');
- if (path.sep === '/') {
- templateData = templateData.replace(/\\/g, '/');
- }
- const nuspecContent = template(templateData)(metadata);
-
- log(`Created NuSpec file:\n${nuspecContent}`);
+ const outputDirectory = path.resolve(options.outputDirectory || 'installer');
+ if (options.remoteReleases) {
+ let cmd = path.join(vendorPath, 'SyncReleases.exe');
+ let args = ['-u', options.remoteReleases, '-r', outputDirectory];
- const nugetOutput = await fsUtils.createTempDir('si-');
- const targetNuspecPath = path.join(nugetOutput, metadata.name + '.nuspec');
-
- await fsUtils.writeFile(targetNuspecPath, nuspecContent);
+ if (useMono) {
+ args.unshift(cmd);
+ cmd = 'mono';
+ }
- let cmd = path.join(vendorPath, 'nuget.exe');
- let args = [
- 'pack', targetNuspecPath,
- '-BasePath', appDirectory,
- '-OutputDirectory', nugetOutput,
- '-NoDefaultExcludes'
- ];
+ if (options.remoteToken) {
+ args.push('-t', options.remoteToken);
+ }
- if (useMono) {
- args.unshift(cmd);
- cmd = monoExe;
+ await spawn(cmd, args);
}
- // Call NuGet to create our package
- log(await spawn(cmd, args));
- const nupkgPath = path.join(nugetOutput, `${metadata.name}.${metadata.version}.nupkg`);
+ // todo fix Squirrel.windows "Sharing violation on path" (avoid copy, use file directly)
+ const squirrelWorkaroundDir = path.join(outputDirectory, '.tmp');
+ await fsUtils.mkdirs(squirrelWorkaroundDir);
+ try {
+ const nupkgPath = path.join(squirrelWorkaroundDir, 'in.nupkg');
+ await pack(metadata, appDirectory, nupkgPath);
+ await releasify(nupkgPath, outputDirectory, options, vendorPath);
+ }
+ finally {
+ await fsUtils.remove(squirrelWorkaroundDir);
+ }
- if (remoteReleases) {
- cmd = path.join(vendorPath, 'SyncReleases.exe');
- args = ['-u', remoteReleases, '-r', outputDirectory];
+ if (options.fixUpPaths !== false) {
+ log('Fixing up paths');
- if (useMono) {
- args.unshift(cmd);
- cmd = monoExe;
+ if (metadata.productName || options.setupExe) {
+ const setupPath = path.join(outputDirectory, options.setupExe || `${metadata.productName}Setup.exe`);
+ const unfixedSetupPath = path.join(outputDirectory, 'Setup.exe');
+ log(`Renaming ${unfixedSetupPath} => ${setupPath}`);
+ await fsUtils.rename(unfixedSetupPath, setupPath);
}
- if (remoteToken) {
- args.push('-t', remoteToken);
+ if (metadata.productName) {
+ const msiPath = path.join(outputDirectory, `${metadata.productName}Setup.msi`);
+ const unfixedMsiPath = path.join(outputDirectory, 'Setup.msi');
+ if (await fsUtils.fileExists(unfixedMsiPath)) {
+ log(`Renaming ${unfixedMsiPath} => ${msiPath}`);
+ await fsUtils.rename(unfixedMsiPath, msiPath);
+ }
}
-
- log(await spawn(cmd, args));
}
+}
+
+function pack(metadata, appDirectory, outFile) {
+ return new Promise(function (resolve, reject) {
+ const archive = archiver('zip', {store: true});
+ const out = fs.createWriteStream(outFile);
+ out.on('close', function () {
+ resolve(outFile);
+ });
+ archive.on('error', reject);
+ archive.pipe(out);
+
+ archive.directory(appDirectory, 'lib/net45');
+
+ archive.append(`
+
+
+
+`, {name: '.rels', prefix: '_rels'});
+
+ const author = metadata.authors || metadata.owners;
+ const copyright = metadata.copyright ||
+ `Copyright © ${new Date().getFullYear()} ${author}`;
+ const version = convertVersion(metadata.version);
+ const nuspecContent = `
+
+
+ ${metadata.name}
+ ${metadata.title}
+ ${version}
+ ${author}
+ ${metadata.owners || metadata.authors}
+ ${metadata.iconUrl}
+ false
+ ${metadata.description}
+ ${copyright}${metadata.extraMetadataSpecs || ''}
+
+`;
+ log(`Created NuSpec file:\n${nuspecContent}`);
+
+ archive.append(nuspecContent, {name: metadata.name + '.nuspec'});
+
+ archive.append(`
+
+
+
+
+
+
+
+
+
+
+`, {name: '[Content_Types].xml'});
+
+ archive.append(`
+
+ ${author}
+ ${metadata.description}
+ ${metadata.name}
+
+ NuGet, Version=3.4.0.653, Culture=neutral, PublicKeyToken=31bf3856ad364e35;Unix 15.4.0.0;.NET Framework 4.5
+ ${metadata.title}
+ ${version}
+`, {name: '1.psmdcp', prefix: 'package/services/metadata/core-properties'});
+
+ archive.finalize();
+ });
+}
- cmd = path.join(vendorPath, 'Update.com');
- args = [
+async function releasify(nupkgPath, outputDirectory, options, vendorPath) {
+ let cmd = path.join(vendorPath, 'Update.com');
+ const args = [
'--releasify', nupkgPath,
'--releaseDir', outputDirectory,
- '--loadingGif', loadingGif
+ '--loadingGif', options.loadingGif ? path.resolve(options.loadingGif) : path.join(__dirname, '..', 'resources', 'install-spinner.gif')
];
- if (useMono) {
+ if (process.platform !== 'win32') {
args.unshift(path.join(vendorPath, 'Update-Mono.exe'));
- cmd = monoExe;
+ cmd = 'mono';
}
+ const {certificateFile, certificatePassword, signWithParams} = options;
if (signWithParams) {
args.push('--signWithParams');
args.push(signWithParams);
@@ -173,25 +224,5 @@ export async function createWindowsInstaller(options) {
args.push('--no-msi');
}
- log(await spawn(cmd, args));
-
- if (options.fixUpPaths !== false) {
- log('Fixing up paths');
-
- if (metadata.productName || options.setupExe) {
- const setupPath = path.join(outputDirectory, options.setupExe || `${metadata.productName}Setup.exe`);
- const unfixedSetupPath = path.join(outputDirectory, 'Setup.exe');
- log(`Renaming ${unfixedSetupPath} => ${setupPath}`);
- await fsUtils.rename(unfixedSetupPath, setupPath);
- }
-
- if (metadata.productName) {
- const msiPath = path.join(outputDirectory, `${metadata.productName}Setup.msi`);
- const unfixedMsiPath = path.join(outputDirectory, 'Setup.msi');
- if (await fsUtils.fileExists(unfixedMsiPath)) {
- log(`Renaming ${unfixedMsiPath} => ${msiPath}`);
- await fsUtils.rename(unfixedMsiPath, msiPath);
- }
- }
- }
-}
+ await spawn(cmd, args);
+}
\ No newline at end of file
diff --git a/src/spawn-promise.js b/src/spawn-promise.js
index 7647967..01fc878 100644
--- a/src/spawn-promise.js
+++ b/src/spawn-promise.js
@@ -1,7 +1,7 @@
import { spawn as spawnOg } from 'child_process';
import { Promise } from 'bluebird';
-const d = require('debug')('electron-windows-installer:spawn');
+const d = require('debug')('electron-windows-installer');
// Public: Maps a process's output into an {Observable}
//
diff --git a/vendor/nuget.exe b/vendor/nuget.exe
deleted file mode 100644
index 8dd7e45..0000000
Binary files a/vendor/nuget.exe and /dev/null differ