Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: partial support for WSL1/WSL2 #373

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1d24bf9
refactor!: replace temp dependency with fs.mkdtemp
malept Oct 15, 2020
a6e65bc
ci: Use Node 10 & latest Windows orb
malept Oct 15, 2020
43b7d6a
chore: update spec ignore
malept Oct 15, 2020
e9204e4
build(deps): upgrade asar to ^3.0.3
malept Oct 15, 2020
b5a16bf
build(deps): upgrade fs-extra to ^9.0.1
malept Oct 15, 2020
05f96ac
build(deps-dev): upgrade @types/fs-extra to 9.0.4
malept Dec 5, 2020
787de3c
build(deps-dev): upgrade @types/lodash.template to 4.5.0
malept Dec 5, 2020
83f7227
build(deps-dev): upgrade @types/node to ^14.14.10
malept Dec 5, 2020
9da4b26
build(deps): upgrade debug to 4.3.1
malept Dec 5, 2020
953df05
chore(deps-dev): upgrade to ESLint 7 & associated config
malept Dec 5, 2020
8080c8f
build(deps-dev): upgrade semantic-release to ^17.3.0
malept Dec 5, 2020
72a4c75
build(deps-dev): upgrade ts-node to ^9.1.0
malept Dec 5, 2020
91a5887
build(deps-dev): upgrade ava to ^3.13.0
malept Dec 5, 2020
6c743f7
build(deps-dev): upgrade typescript to ^4.1.2
malept Dec 5, 2020
1c642c1
ci: install the correct Node 10 for macOS/Windows
malept Dec 5, 2020
9754521
ci: ensure yarn is installed on Windows
malept Dec 5, 2020
9696587
ci: try installing yarn on Windows again
malept Dec 5, 2020
a739f9b
ci: debug where it thinks Node is on Windows
malept Dec 5, 2020
3ff61d9
ci: remove debug
malept Dec 5, 2020
87e98df
refactor: use the rcedit module for some WSL2 compatibility
malept Dec 5, 2020
6bbf31b
refactor: use cross-spawn-windows-exe instead of handling mono/wine o…
malept Dec 5, 2020
1c50044
build(deps): upgrade transitive dependencies
malept Dec 5, 2020
f1aca6c
docs: clean up README
malept Dec 5, 2020
d631f43
build(deps): upgrade cross-spawn-windows-exe & rcedit
malept Dec 14, 2020
5943841
build(deps-dev): upgrade dependencies
malept Dec 14, 2020
8654f71
build(deps): upgrade transitive dependencies
malept Jul 19, 2021
0401fea
refactor: use cross-spawn-windows-exe to run 7z.exe
malept Jul 19, 2021
427dd9b
ci: re-enable linux jobs to see if the error persists
malept Jul 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,23 @@ step-install-os-dependencies: &step-install-os-dependencies
wine64 hostname
;;
Darwin)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm install 10
nvm alias default 10
echo 'export NVM_DIR=${HOME}/.nvm' >> $BASH_ENV
echo "[ -s '${NVM_DIR}/nvm.sh' ] && . '${NVM_DIR}/nvm.sh'" >> $BASH_ENV
brew install --cask xquartz wine-stable
brew install mono
wine64 hostname
;;
Windows*|CYGWIN*|MINGW*|MSYS*)
nvm install 10.22.0
nvm use 10.22.0
nvm list
npm.cmd install -g yarn
;;
esac

steps-linux-win: &steps-linux-win
Expand All @@ -75,25 +88,25 @@ steps-mac: &steps-mac

version: 2.1
orbs:
win: circleci/windows@1.0.0
win: circleci/windows@2.4.0
jobs:
test-linux:
docker:
- image: circleci/node@sha256:44c6136b6b55003fa12321aa1eb790a5a6482edb461227cb56daf488178d04dc
- image: circleci/node:10
<<: *steps-linux-win
test-mac:
macos:
xcode: "11.1.0"
<<: *steps-mac
test-windows:
executor:
name: win/vs2019
name: win/default
shell: bash.exe
<<: *steps-linux-win

release:
docker:
- image: circleci/node:10.15
- image: circleci/node:10
steps:
- checkout
- *step-restore-cache
Expand All @@ -104,12 +117,12 @@ workflows:
test_and_release:
# Run the test jobs first, then the release only when all the test jobs are successful
jobs:
# - test-linux
- test-linux
- test-mac
- test-windows
- release:
requires:
# - test-linux
- test-linux
- test-mac
- test-windows
filters:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ npm-debug.log
SquirrelSetup.log
.node-version
.DS_Store
spec/fixtures/app/Squirrel.exe
spec/fixtures/app/Update.exe
vendor/7z.dll
vendor/7z.exe
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# Electron Installer

[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/bq6c06suq5abb66s/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/windows-installer/branch/master)
[![CircleCI](https://circleci.com/gh/electron/windows-installer.svg?style=svg)](https://circleci.com/gh/electron/windows-installer)

NPM module that builds Windows installers for
[Electron](https://github.com/electron/electron) apps using
[Electron](https://electronjs.org) apps using
[Squirrel](https://github.com/Squirrel/Squirrel.Windows).

## Installing
Expand All @@ -24,8 +23,8 @@ const electronInstaller = require('electron-winstaller');
Then do a build like so..

```javascript
// NB: Use this syntax within an async function, Node does not have support for
// top-level await as of Node 12.
// Note: top-level await exists in Node >= 14.8.0. In earlier versions of Node, please wrap in an
// async function.
try {
await electronInstaller.createWindowsInstaller({
appDirectory: '/tmp/build/my-app-64',
Expand Down
36 changes: 20 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,36 @@
"semantic-release": "semantic-release"
},
"dependencies": {
"asar": "^2.0.1",
"asar": "^3.0.3",
"cross-spawn-windows-exe": "^1.0.0",
"debug": "^4.1.1",
"fs-extra": "^7.0.1",
"fs-extra": "^9.0.1",
"lodash.template": "^4.2.2",
"temp": "^0.9.0"
"rcedit": "^3.0.0"
},
"devDependencies": {
"@continuous-auth/semantic-release-npm": "^2.0.0",
"@types/fs-extra": "^5.0.5",
"@types/debug": "^4.1.5",
"@types/fs-extra": "^9.0.2",
"@types/lodash.template": "^4.4.6",
"@types/node": "^12.0.0",
"@types/temp": "^0.8.34",
"@typescript-eslint/eslint-plugin": "^1.7.0",
"@typescript-eslint/parser": "^1.7.0",
"ava": "^2.0.0",
"eslint": "^5.14.1",
"eslint-plugin-ava": "^7.1.0",
"semantic-release": "^15.13.3",
"ts-node": "^8.1.0",
"typescript": "^3.4.5"
"@types/node": "^14.14.10",
"@typescript-eslint/eslint-plugin": "^4.9.0",
"@typescript-eslint/parser": "^4.9.0",
"ava": "^3.13.0",
"eslint": "^7.14.0",
"eslint-plugin-ava": "^11.0.0",
"semantic-release": "^17.3.0",
"ts-node": "^9.1.0",
"typescript": "^4.1.2"
},
"engines": {
"node": ">=8.0.0"
"node": ">=10.17.0"
},
"resolutions": {
"semantic-release/@semantic-release/github": "7.2.1",
"semantic-release/@semantic-release/npm": "7.1.1"
},
"ava": {
"compileEnhancements": false,
"extensions": [
"ts"
],
Expand Down
18 changes: 8 additions & 10 deletions spec/installer-spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import test from 'ava';
import path from 'path';
import { createTempDir } from '../src/temp-utils';
import fs from 'fs-extra';
import { createWindowsInstaller } from '../src';
import spawn from '../src/spawn-promise';
import debug from 'debug';
import * as fs from 'fs-extra';
import * as path from 'path';
import { spawnExe } from 'cross-spawn-windows-exe';
import test from 'ava';

const log = require('debug')('electron-windows-installer:spec');
const log = debug('electron-windows-installer:spec');

const fixtureAppDirectory = path.join(__dirname, 'fixtures/app');

function spawn7z(args: string[]): Promise<string> {
async function spawn7z(args: string[]): Promise<string> {
const sevenZipPath = path.join(__dirname, '..', 'vendor', '7z.exe');
const wineExe = process.arch === 'x64' ? 'wine64' : 'wine';
return process.platform !== 'win32'
? spawn(wineExe, [sevenZipPath, ...args])
: spawn(sevenZipPath, args);
return spawnExe(sevenZipPath, args);
}

async function createTempAppDirectory(): Promise<string> {
Expand Down
108 changes: 32 additions & 76 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import * as asar from 'asar';
import { createTempDir } from './temp-utils';
import debug from 'debug';
import * as fs from 'fs-extra';
import { Metadata, Options, PersonMetadata } from './options';
import * as path from 'path';
import spawn from './spawn-promise';
import rcedit from 'rcedit';
import { canRunWindowsExeNatively, spawnDotNet } from 'cross-spawn-windows-exe';
import template from 'lodash.template';

export { Options } from './options';

const log = require('debug')('electron-windows-installer:main');
const log = debug('electron-windows-installer:main');

export function convertVersion(version: string): string {
const parts = version.split('-');
Expand All @@ -21,24 +23,9 @@ export function convertVersion(version: string): string {
}
}


export async function createWindowsInstaller(options: Options): Promise<void> {
let useMono = false;

const monoExe = 'mono';
const wineExe = process.arch === 'x64' ? 'wine64' : '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;
const { appDirectory } = options;
let { outputDirectory, loadingGif } = options;
outputDirectory = path.resolve(outputDirectory || 'installer');

const vendorPath = path.join(__dirname, '..', 'vendor');
Expand All @@ -47,24 +34,13 @@ export async function createWindowsInstaller(options: Options): Promise<void> {

await fs.copy(vendorUpdate, appUpdate);
if (options.setupIcon && (options.skipUpdateIcon !== true)) {
let cmd = path.join(vendorPath, 'rcedit.exe');
let args = [
appUpdate,
'--set-icon', options.setupIcon
];

if (useMono) {
args.unshift(cmd);
cmd = wineExe;
}

await spawn(cmd, args);
await rcedit(appUpdate, { icon: options.setupIcon });
}

const defaultLoadingGif = path.join(__dirname, '..', 'resources', 'install-spinner.gif');
loadingGif = loadingGif ? path.resolve(loadingGif) : defaultLoadingGif;

let { certificateFile, certificatePassword, remoteReleases, signWithParams, remoteToken } = options;
const { certificateFile, certificatePassword, remoteReleases, signWithParams, remoteToken } = options;

const metadata: Metadata = {
description: '',
Expand Down Expand Up @@ -94,7 +70,6 @@ export async function createWindowsInstaller(options: Options): Promise<void> {
if (typeof (metadata.author) === 'string') {
metadata.authors = metadata.author;
} else {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
metadata.authors = (metadata.author || ({} as PersonMetadata)).name || '';
}
}
Expand Down Expand Up @@ -125,87 +100,68 @@ export async function createWindowsInstaller(options: Options): Promise<void> {

log(`Created NuSpec file:\n${nuspecContent}`);

const nugetOutput = await createTempDir('si-');
const targetNuspecPath = path.join(nugetOutput, metadata.name + '.nuspec');
const nugetOutputDir = await createTempDir('electron-winstaller-nuget-');
const targetNuspecPath = path.join(nugetOutputDir, metadata.name + '.nuspec');

await fs.writeFile(targetNuspecPath, nuspecContent);

let cmd = path.join(vendorPath, 'nuget.exe');
let args = [
// Call NuGet to create our package
log(await spawnDotNet(path.join(vendorPath, 'nuget.exe'), [
'pack', targetNuspecPath,
'-BasePath', appDirectory,
'-OutputDirectory', nugetOutput,
'-OutputDirectory', nugetOutputDir,
'-NoDefaultExcludes'
];

if (useMono) {
args.unshift(cmd);
cmd = monoExe;
}

// Call NuGet to create our package
log(await spawn(cmd, args));
const nupkgPath = path.join(nugetOutput, `${metadata.name}.${metadata.version}.nupkg`);
]));
const nupkgPath = path.join(nugetOutputDir, `${metadata.name}.${metadata.version}.nupkg`);

if (remoteReleases) {
cmd = path.join(vendorPath, 'SyncReleases.exe');
args = ['-u', remoteReleases, '-r', outputDirectory];

if (useMono) {
args.unshift(cmd);
cmd = monoExe;
}
const syncReleasesArgs = ['-u', remoteReleases, '-r', outputDirectory];

if (remoteToken) {
args.push('-t', remoteToken);
syncReleasesArgs.push('-t', remoteToken);
}

log(await spawn(cmd, args));
log(await spawnDotNet(path.join(vendorPath, 'SyncReleases.exe'), syncReleasesArgs));
}

cmd = path.join(vendorPath, 'Squirrel.exe');
args = [
const squirrelCmd = path.join(vendorPath, canRunWindowsExeNatively() ? 'Squirrel.exe' : 'Squirrel-Mono.exe');
const squirrelArgs = [
'--releasify', nupkgPath,
'--releaseDir', outputDirectory,
'--loadingGif', loadingGif
];

if (useMono) {
args.unshift(path.join(vendorPath, 'Squirrel-Mono.exe'));
cmd = monoExe;
}

if (signWithParams) {
args.push('--signWithParams');
squirrelArgs.push('--signWithParams');
if (!signWithParams.includes('/f') && !signWithParams.includes('/p') && certificateFile && certificatePassword) {
args.push(`${signWithParams} /a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
squirrelArgs.push(`${signWithParams} /a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
} else {
args.push(signWithParams);
squirrelArgs.push(signWithParams);
}
} else if (certificateFile && certificatePassword) {
args.push('--signWithParams');
args.push(`/a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
squirrelArgs.push('--signWithParams');
squirrelArgs.push(`/a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
}

if (options.setupIcon) {
args.push('--setupIcon');
args.push(path.resolve(options.setupIcon));
squirrelArgs.push('--setupIcon');
squirrelArgs.push(path.resolve(options.setupIcon));
}

if (options.noMsi) {
args.push('--no-msi');
squirrelArgs.push('--no-msi');
}

if (options.noDelta) {
args.push('--no-delta');
squirrelArgs.push('--no-delta');
}

if (options.frameworkVersion) {
args.push('--framework-version');
args.push(options.frameworkVersion);
squirrelArgs.push('--framework-version');
squirrelArgs.push(options.frameworkVersion);
}

log(await spawn(cmd, args));
log(await spawnDotNet(squirrelCmd, squirrelArgs));

if (options.fixUpPaths !== false) {
log('Fixing up paths');
Expand Down
Loading