630 changes: 630 additions & 0 deletions resources/win/FusionSdk.nsh

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions resources/win/eula.txt
@@ -0,0 +1,62 @@
This End-User License Agreement (EULA) is a legal agreement between you (either as an individual or on behalf of an entity) and Alexandru Rosianu regarding your use of Messenger for Desktop for OS X, Windows and Linux and associated documentation (the "Software"). This EULA includes the Terms and Conditions (https://messengerfordesktop.com/terms.html) and Privacy Policy (https://messengerfordesktop.com/privacy.html). IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS EULA, DO NOT INSTALL, USE OR COPY THE SOFTWARE.

Summary
You must agree to all of the terms of this EULA to use this Software.

If so, you may use the Software for free and for any lawful purpose.

This Software automatically communicates with Alexandru Rosianu's server(s) for three reasons: (1) to receive and install updates; (2) to send error reports; and (3) to send anonymized usage information. You can view the source code to see what information is sent, and you may opt out of sending the anonymized usage data.

This Software is provided "as-is" with no warranties, and you agree that Alexandru Rosianu is not liable for anything you do with it.

You really ought to just go ahead and read the whole EULA. It's not all that long. You should not only rely on this summary.

The Agreement
By downloading, installing, using, or copying the Software, you accept and agree to be bound by the terms of this EULA. If you do not agree to all of the terms of this EULA, you may not download, install, use or copy the Software.

The License
This EULA entitles you to install as many copies of the Software as you want, and use the Software for any lawful purpose consistent with this EULA. Your license to use the Software is expressly conditioned upon your agreement to all of the terms of this EULA. This software is licensed, not sold. Alexandru Rosianu reserves all other rights not granted by this EULA.

The Restrictions
When using the Software you must use it in a manner that complies with the applicable laws in the jurisdiction(s) in which you use the Software.

You may not sell, resell, rent, lease or exchange the Software for anything of value.

You may redistribute the software, but it must include this EULA and you may not repackage or bundle the Software with any other software.

Since the Software is open source, you are free to copy its source code (within the limits of the MIT license) and create your own clone of the Software, which is not bound by this EULA.

Privacy Notices
The Software automatically communicates with Alexandru Rosianu's server(s) for three purposes: (1) updating the Software; (2) sending error reports; and (3) sending anonymized usage data so I may improve the Software. If you are a programmer, you may view the source code of the Software to learn more about the specific information that is sent. You may opt out of sending anonymized usage data, crash reporting and update checks by disabling these features from the Software menu.

Error Reports. In order to help improve the Software, when the Software encounters certain errors, it will automatically send some information to Alexandru Rosianu's server(s) about the error. Reports include data such as (but not only): information about the crash, your Operating System type, Software version. If you do not want to send crash reports to Alexandru Rosianu, you may opt out by changing your settings in the Software menu.

Anonymized Usage Data. Alexandru Rosianu collects anonymized data about your usage of the Software to help make it more awesome. If you do not want to send anonymized usage data to Alexandru Rosianu, you may opt out by changing your settings in the Software menu.

Open-Source Notices
Certain components of the Software may be subject to open-source software licenses ("Open-Source Components"), which means any software license approved as open-source licenses by the Open Source Initiative or any substantially similar licenses, including without limitation any license that, as a condition of distribution of the software licensed under such license, requires that the distributor make the software available in source code format. The Software documentation includes copies of the licenses applicable to the Open-Source Components.

To the extent there is conflict between the license terms covering the Open-Source Components and this EULA, the terms of such licenses will apply in lieu of the terms of this EULA. To the extent the terms of the licenses applicable to Open-Source Components prohibit any of the restrictions in this Agreement with respect to such Open-Source Component, such restrictions will not apply to such Open-Source Component.

The Software itself is open source and is available on GitHub at github.com/Aluxian/Facebook-Messenger-Desktop.

Intellectual Property Notices
The Software makes use of WhatsApp Web, which is the property of WhatsApp Inc. The WhatsApp logo, WhatsApp Web app, brand identity and other property rights are WhatsApp Inc's exclusive property and not Alexandru Rosianu's.

Disclaimers and Limitations on Liability
THE SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND NO WARRANTY, EITHER EXPRESS OR IMPLIED, IS GIVEN. YOUR USE OF THE SOFTWARE IS AT YOUR SOLE RISK. Alexandru Rosianu does not warrant that (i) the Software will meet your specific requirements; (ii) the Software is fully compatible with any particular platform; (iii) your use of the Software will be uninterrupted, timely, secure, or error-free; (iv) the results that may be obtained from the use of the Software will be accurate or reliable; (v) the quality of any products, services, information, or other material purchased or obtained by you through the Software will meet your expectations; or (vi) any errors in the Software will be corrected.

YOU EXPRESSLY UNDERSTAND AND AGREE THAT ALEXANDRU ROSIANU SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES, INCLUDING BUT NOT LIMITED TO, DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER INTANGIBLE LOSSES (EVEN IF ALEXANDRU ROSIANU HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES) RELATED TO THE SOFTWARE, including, for example: (i) the use or the inability to use the Software; (ii) the cost of procurement of substitute goods and services resulting from any goods, data, information or services purchased or obtained or messages received or transactions entered into through or from the Software; (iii) unauthorized access to or alteration of your transmissions or data; (iv) statements or conduct of any third-party on the Software; (v) or any other matter relating to the Software.

Alexandru Rosianu reserves the right at any time and from time to time to modify or discontinue, temporarily or permanently, the Software (or any part thereof) with or without notice. Alexandru Rosianu shall not be liable to you or to any third-party for any modification, price change, suspension or discontinuance of the Software.

Miscellanea
The failure of Alexandru Rosianu to exercise or enforce any right or provision of this EULA shall not constitute a waiver of such right or provision.

This EULA constitutes the entire agreement between you and Alexandru Rosianu and governs your use of the Software, superseding any prior agreements between you and Alexandru Rosianu (including, but not limited to, any prior versions of the EULA).

You agree that this EULA and your use of the Software are governed under Romanian law and any dispute related to the Software must be brought in a tribunal of competent jurisdiction located in or near Bucharest, Romania.

Please send any questions about this EULA to me@aluxian.com.

The last update to this EULA was posted on May 6, 2016.
153 changes: 153 additions & 0 deletions resources/win/installer.nsi
@@ -0,0 +1,153 @@
!define IS_IC_FUSION_STR_PRODUCT_TITLE "{{ productName }}"
!define IS_IC_FUSION_STR_CHANNEL_ID ""
!define IS_IC_FUSION_STR_AUTH_KEY "$%IS_IC_FUSION_STR_AUTH_KEY%"


/*************************************
General
***********************************/
#Name and file
Name "{{ productName }}"
BrandingText "{{& homepage }}"
OutFile "..\..\..\dist\{{ name }}-{{ version }}-win32-nsis.exe"
#Specifies the requested execution level for Windows Vista and higher
RequestExecutionLevel admin
#Tells the compiler whether or not to do datablock optimizations.
SetDatablockOptimize on
#Show installation details
ShowInstDetails show


/*************************************
Includes
***********************************/
# Use Modern UI to make the installer look nice
!include "MUI2.nsh"
# Include Sections header so that we can manipulate section properties in .onInit
!include "Sections.nsh"
!include "FusionSdk.nsh"


/*************************************
Reserve files
***********************************/
!insertmacro MUI_RESERVEFILE_LANGDLL
# Reserves the Fusion.dll file
!insertmacro FusionReserveFile


/*************************************
Modern UI Configuration
***********************************/
# MUI Settings
!define MUI_ABORTWARNING
# define this to use custom function when user aborting (if FusionOnUserAbort been used)
!define MUI_CUSTOMFUNCTION_ABORT "customOnUserAbort"
# custom icon
!define MUI_ICON "app.ico"
# offer to launch app after install
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_TEXT "Start {{ productName }}"
!define MUI_FINISHPAGE_RUN_FUNCTION "StartAppAfterInstall"

/*************************************
Installer pages
***********************************/
# Welcome page
!insertmacro MUI_PAGE_WELCOME
# License page
!insertmacro MUI_PAGE_LICENSE "eula.txt"
# Fusion offers page
!insertmacro FusionOffersPage
# Perform installation (executes each enabled Section)
!insertmacro MUI_PAGE_INSTFILES
# Finish page
!insertmacro MUI_PAGE_FINISH


/*************************************
Language support
***********************************/
!insertmacro MUI_LANGUAGE "English"


/*************************************
Installer sections
***********************************/
Section "-FusionOffersInstallation"
# Installs the accepted offers
!insertmacro FusionInstallOffers
SectionEnd
Section "Squirrel Install" SecSquirrel
SetOutPath "$TEMP"
File "..\..\..\dist\{{ name }}-{{ version }}-win32-setup-for-nsis.exe"
ExecWait '"$TEMP\{{ name }}-{{ version }}-win32-setup-for-nsis.exe" --silent'
DetailPrint "Copying files..."
Var /GLOBAL SW_TOTAL_TIME_WAITED_MS
StrCpy $SW_TOTAL_TIME_WAITED_MS "0"
Delete "$LOCALAPPDATA\{{ name }}\SquirrelSetup.log"

WaitUntilSquirrelInstalled:
# initial wait
Sleep 1000

# increment and check timeout
IntOp $SW_TOTAL_TIME_WAITED_MS $SW_TOTAL_TIME_WAITED_MS + 1000
IntCmp $SW_TOTAL_TIME_WAITED_MS 60000 0 0 SquirrelInstalledSkipped

# check if log file exists
DetailPrint "Checking if SquirrelSetup.log exists..."
IfFileExists "$LOCALAPPDATA\{{ name }}\SquirrelSetup.log" 0 WaitUntilSquirrelInstalled
Sleep 3000

# file exists, probably it worked
# try to delete the installer
DetailPrint "Deleting Squirrel installer..."
ClearErrors
Delete "$TEMP\{{ name }}-{{ version }}-win32-setup-for-nsis.exe"

# check if delete worked
IfErrors 0 SquirrelDeleteWorked
DetailPrint "Could not delete Squirrel installer, trying again..."
Goto WaitUntilSquirrelInstalled

SquirrelDeleteWorked:
DetailPrint "Install finished, cleaning up..."
Goto SquirrelInstalledDone

SquirrelInstalledSkipped:
DetailPrint "Checking for SquirrelSetup.log timed out"
DetailPrint "Skipping..."

SquirrelInstalledDone:

Sleep 3000
SectionEnd


/*************************************
NSIS Callbacks
***********************************/
Function .onInit
; Display a language selection dialog box for languages
; This will only show if you have added multiple languages
; using the MUI_LANGUAGE macro.
!insertmacro MUI_LANGDLL_DISPLAY
; Initialize Fusion
!insertmacro FusionInit "${IS_IC_FUSION_STR_AUTH_KEY}" "${IS_IC_FUSION_STR_PRODUCT_TITLE}" "${IS_IC_FUSION_STR_CHANNEL_ID}" "$LANGUAGE"
FunctionEnd
Function .onInstSuccess
!insertmacro FusionOnInstSuccess
FunctionEnd
Function .onInstFailed
!insertmacro FusionOnInstFailed
FunctionEnd
Function .onGUIEnd
!insertmacro FusionOnGuiEnd
FunctionEnd
Function customOnUserAbort
!insertmacro FusionOnUserAbort
FunctionEnd
Function StartAppAfterInstall
ExecShell "" "$LOCALAPPDATA\{{ name }}\Update.exe" '--processStart "{{ productName }}.exe"'
FunctionEnd
8 changes: 4 additions & 4 deletions src/package.json
@@ -1,7 +1,7 @@
{
"name": "messengerfordesktop",
"productName": "Messenger for Desktop",
"version": "2.0.0",
"version": "2.0.1",
"versionChannel": "beta",
"description": "A simple & beautiful desktop client for Facebook Messenger.",
"wvUrl": "https://www.messenger.com/login",
Expand Down Expand Up @@ -56,20 +56,20 @@
"author": "Alexandru Rosianu <me@aluxian.com>",
"authorName": "Alexandru Rosianu",
"copyright": "Copyright © Alexandru Rosianu",
"homepage": "https://messengerfordesktop.com/",
"homepage": "https://messengerfordesktop.com",
"repository": {
"type": "git",
"url": "https://github.com/Aluxian/Facebook-Messenger-Desktop.git"
},
"virtualUrl": "http://app.messengerfordesktop.com",
"piwik": {
"serverUrl": "{{& PIWIK_SERVER_URL }}",
"siteId": "1"
"siteId": "2"
},
"sentry": {
"dsn": "{{& SENTRY_DSN_PRIVATE }}"
},
"electronVersion": "v1.3.4",
"electronVersion": "v1.3.5",
"distrib": "unset",
"portable": false,
"buildNum": 0,
Expand Down
8 changes: 2 additions & 6 deletions src/scripts/browser/managers/main-window-manager.js
Expand Up @@ -78,12 +78,8 @@ class MainWindowManager extends EventEmitter {
this.window.on('move', saveBounds);

// Restore full screen state
if (!platform.isLinux) {
const isFullScreen = prefs.get('window-full-screen');
this.window.setFullScreen(isFullScreen);
// doesn't work correctly on Linux: setFullScreen makes
// the app full screen even if it's called with false
}
const isFullScreen = prefs.get('window-full-screen');
this.window.setFullScreen(isFullScreen);

// Finally, load the app html
this.window.loadURL(global.manifest.virtualUrl + '/html/app.html');
Expand Down
24 changes: 19 additions & 5 deletions src/scripts/browser/managers/tray-manager.js
@@ -1,5 +1,5 @@
import EventEmitter from 'events';
import {Menu, Tray} from 'electron';
import {Menu, Tray, nativeImage} from 'electron';

import filePaths from 'common/utils/file-paths';
import platform from 'common/utils/platform';
Expand Down Expand Up @@ -29,8 +29,14 @@ class TrayManager extends EventEmitter {
}

if (platform.isDarwin) {
this.tray = new Tray(filePaths.getImagePath('trayBlackTemplate.png'));
this.tray.setPressedImage(filePaths.getImagePath('trayWhiteTemplate.png'));
const imagePath = filePaths.getImagePath('trayBlackTemplate.png');
const image = nativeImage.createFromPath(imagePath);

const pressedImagePath = filePaths.getImagePath('trayWhiteTemplate.png');
const pressedImage = nativeImage.createFromPath(pressedImagePath);

this.tray = new Tray(image);
this.tray.setPressedImage(pressedImage);

// Show the notifications count
if (this.notifManager.unreadCount) {
Expand All @@ -39,7 +45,11 @@ class TrayManager extends EventEmitter {
} else {
const imgExt = platform.isWindows ? 'ico' : 'png';
const iconName = this.notifManager.unreadCount ? 'trayAlert' : 'tray';
this.tray = new Tray(filePaths.getImagePath(iconName + '.' + imgExt));

const imagePath = filePaths.getImagePath(iconName + '.' + imgExt);
const image = nativeImage.createFromPath(imagePath);

this.tray = new Tray(image);
}

this.menu = Menu.buildFromTemplate(template());
Expand Down Expand Up @@ -107,7 +117,11 @@ class TrayManager extends EventEmitter {
} else {
const imgExt = platform.isWindows ? 'ico' : 'png';
const iconName = count ? 'trayAlert' : 'tray';
this.tray.setImage(filePaths.getImagePath(iconName + '.' + imgExt));

const imagePath = filePaths.getImagePath(iconName + '.' + imgExt);
const image = nativeImage.createFromPath(imagePath);

this.tray.setImage(image);
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/scripts/browser/menus/expressions/expr-click.js
Expand Up @@ -72,6 +72,9 @@ export function openUrl (url) {
*/
export function sendToWebView (channel, ...valueExprs) {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
const values = valueExprs.map((e) => e.apply(this, arguments));
browserWindow.webContents.send('fwd-webview', channel, ...values);
};
Expand Down Expand Up @@ -120,6 +123,9 @@ export function showWindow () {
*/
export function toggleFullScreen () {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
const newState = !browserWindow.isFullScreen();
browserWindow.setFullScreen(newState);
};
Expand All @@ -130,6 +136,9 @@ export function toggleFullScreen () {
*/
export function toggleDevTools () {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
browserWindow.toggleDevTools();
};
}
Expand All @@ -139,6 +148,9 @@ export function toggleDevTools () {
*/
export function toggleMenuBar () {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
const newState = !browserWindow.isMenuBarVisible();
browserWindow.setMenuBarVisibility(newState);
};
Expand All @@ -149,6 +161,9 @@ export function toggleMenuBar () {
*/
export function floatOnTop (flagExpr) {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
const flag = flagExpr.apply(this, arguments);
browserWindow.setAlwaysOnTop(flag);
};
Expand Down Expand Up @@ -225,6 +240,9 @@ export function hideDockBadge (flagExpr) {
*/
export function hideTaskbarBadge (flagExpr) {
return function (menuItem, browserWindow) {
if (!browserWindow) {
browserWindow = global.application.mainWindowManager.window;
}
const flag = flagExpr.apply(this, arguments);
if (!flag) {
browserWindow.setOverlayIcon(null, '');
Expand Down
11 changes: 11 additions & 0 deletions src/scripts/browser/menus/expressions/expr-value.js
Expand Up @@ -57,3 +57,14 @@ export function themeCss (nameExpr, callback) {
.catch(logError);
};
}

/**
* Gets the css content of the given style.
*/
export function styleCss (styleName, callback) {
return function () {
files.getStyleCss(styleName)
.then((css) => callback(css).apply(this, arguments))
.catch(logError);
};
}
21 changes: 18 additions & 3 deletions src/scripts/browser/menus/templates/main-edit.js
Expand Up @@ -69,7 +69,12 @@ export default {
accelerator: 'CmdOrCtrl+Alt+S',
needsWindow: true,
click: $.all(
$.sendToWebView('spell-checker', $.key('checked'), $.pref('spell-checker-auto-correct'), $.pref('spell-checker-language')),
$.sendToWebView(
'spell-checker',
$.key('checked'),
$.pref('spell-checker-auto-correct'),
$.pref('spell-checker-language')
),
$.updateSibling('spell-checker-auto-correct', 'enabled', $.key('checked')),
$.updateSibling('spell-checker-language', 'enabled', $.key('checked')),
$.setPref('spell-checker-check', $.key('checked'))
Expand All @@ -84,7 +89,12 @@ export default {
needsWindow: true,
allow: false,
click: $.all(
$.sendToWebView('spell-checker', $.pref('spell-checker-check'), $.key('checked'), $.pref('spell-checker-language')),
$.sendToWebView(
'spell-checker',
$.pref('spell-checker-check'),
$.key('checked'),
$.pref('spell-checker-language')
),
$.setPref('spell-checker-auto-correct', $.key('checked'))
),
parse: $.all(
Expand All @@ -103,7 +113,12 @@ export default {
click: $.all(
$.ifTrue(
$.pref('spell-checker-check'),
$.sendToWebView('spell-checker', $.pref('spell-checker-check'), $.pref('spell-checker-auto-correct'), $.key('langCode'))
$.sendToWebView(
'spell-checker',
$.pref('spell-checker-check'),
$.pref('spell-checker-auto-correct'),
$.key('langCode')
)
),
$.setPref('spell-checker-language', $.key('langCode'))
)
Expand Down
15 changes: 15 additions & 0 deletions src/scripts/browser/menus/templates/main-view.js
Expand Up @@ -45,6 +45,21 @@ export default {
click: $.toggleMenuBar()
}, {
type: 'separator'
}, {
type: 'checkbox',
label: 'Auto Hide Sidebar',
needsWindow: true,
click: $.all(
$.styleCss('auto-hide-sidebar', (css) =>
$.sendToWebView('apply-sidebar-auto-hide', $.key('checked'), $.val(css))
),
$.setPref('sidebar-auto-hide', $.key('checked'))
),
parse: $.all(
$.setLocal('checked', $.pref('sidebar-auto-hide'))
)
}, {
type: 'separator'
}, {
label: 'N&ew Conversation',
accelerator: 'CmdOrCtrl+N',
Expand Down
1 change: 1 addition & 0 deletions src/scripts/browser/utils/prefs-defaults.js
Expand Up @@ -16,6 +16,7 @@ const defaults = {
'show-notifications-badge': true,
'show-tray': platform.isWindows,
'show-dock': true,
'sidebar-auto-hide': false,
'spell-checker-check': false,
'spell-checker-auto-correct': false,
'spell-checker-language': defaultSpellCheckerLanguage,
Expand Down
17 changes: 17 additions & 0 deletions src/scripts/renderer/preload/events.js
Expand Up @@ -46,6 +46,23 @@ ipcRenderer.on('apply-theme', function (event, css) {
styleBlock.innerHTML = css;
});

// Insert or remove the style required to auto-hide the sidebar
ipcRenderer.on('apply-sidebar-auto-hide', function (event, enabled, css) {
let styleBlock = document.getElementById('sidebarAutoHide');

if (enabled && !styleBlock) {
styleBlock = document.createElement('style');
styleBlock.id = 'sidebarAutoHide';
styleBlock.type = 'text/css';
styleBlock.innerHTML = css;
document.head.appendChild(styleBlock);
}

if (!enabled && styleBlock) {
styleBlock.parentNode.removeChild(styleBlock);
}
});

// Add the selected misspelling to the dictionary
ipcRenderer.on('add-selection-to-dictionary', function () {
SpellChecker.add(document.getSelection().toString());
Expand Down
9 changes: 9 additions & 0 deletions src/scripts/renderer/webview/listeners.js
Expand Up @@ -85,6 +85,15 @@ webView.addEventListener('dom-ready', function () {
}
}

// Restore the sidebar auto-hide setting
const sidebarAutoHide = prefs.get('sidebar-auto-hide');
if (sidebarAutoHide) {
log('restoring sidebar auto-hide', sidebarAutoHide);
files.getStyleCss('auto-hide-sidebar')
.then((css) => webView.send('apply-sidebar-auto-hide', sidebarAutoHide, css))
.catch(logError);
}

// Restore the default zoom level
const zoomLevel = prefs.get('zoom-level');
if (zoomLevel) {
Expand Down
15 changes: 15 additions & 0 deletions src/styles/app.less
Expand Up @@ -3,3 +3,18 @@ html, body, #wv {
height: 100%;
margin: 0px;
}

/* Remove the 'install mobile app' bar */
._s15 {
display: none;
}

/* Fix the scrollbar bug for some languages */
._kmc {
line-height: 1.29;
}

/* Fix huge website previews */
._3058._15gf {
max-width: 800px;
}
24 changes: 24 additions & 0 deletions src/styles/auto-hide-sidebar.less
@@ -0,0 +1,24 @@
/* @source: https://userstyles.org/styles/112567/facebook-messanger-nice-tidy-and-more-responsive */
@media all and (min-width: 641px) {
._1enh {
transition: transform 0.4s ease-in-out, box-shadow 0.4s ease-in-out;
position: relative;
z-index: 1000;
width: 320px !important;
margin-left: -310px;
background: white;
}

._1enh:hover {
transform: translate(310px);
box-shadow: 0px 0px 0px 3000px rgba(0, 0, 0, 0.6);
}

._4sp8 {
min-width: 320px;
}

._1ht3 {
background-color: #cfe8ff !important;
}
}
6 changes: 6 additions & 0 deletions tasks/clean.coffee
Expand Up @@ -11,22 +11,26 @@ gulp.task 'clean:build:darwin64', ['download:darwin64'], ->
'./build/darwin64/' + manifest.productName + '.app/Contents/Resources/default_app.asar'
'./build/darwin64/' + manifest.productName + '.app/Contents/Resources/electron.icns'
]
.then (result) -> console.log result

# Remove the default_app folder inside the linux builds
['linux32', 'linux64'].forEach (dist) ->
gulp.task 'clean:build:' + dist, ['download:' + dist], ->
del './build/' + dist + '/opt/' + manifest.name + '/resources/default_app.asar'
.then (result) -> console.log result

# Remove the default_app folder inside the win32 build
gulp.task 'clean:build:win32', ['download:win32'], ->
del './build/win32/resources/default_app.asar'
.then (result) -> console.log result

# Clean build dist for the current platform by default
gulp.task 'clean:build', ['clean:build:' + platform()]

# Clean all the dist files for darwin64 and make sure the dir exists
gulp.task 'clean:dist:darwin64', ->
del './dist/' + manifest.productName + '-' + manifest.version + '-osx.dmg'
.then (result) -> console.log result
.then -> fs.ensureDirAsync './dist'

# Just ensure the dir exists (dist files are overwritten)
Expand All @@ -37,9 +41,11 @@ gulp.task 'clean:dist:darwin64', ->
# Remove packages from previous releases
gulp.task 'clean:prev-releases:win32', ->
del [
'./dist/' + manifest.name + '-*-setup-for-nsis.exe'
'./dist/' + manifest.name + '-*-full.nupkg'
'!./dist/' + manifest.name + '-' + manifest.version + '-full.nupkg'
]
.then (result) -> console.log result

# Clean dist for the current platform by default
gulp.task 'clean:dist', ['clean:dist:' + platform()]
99 changes: 98 additions & 1 deletion tasks/pack.coffee
@@ -1,7 +1,6 @@
request = require 'request'
path = require 'path'
args = require './args'
fs = require 'fs'

asar = require 'asar'
async = require 'async'
Expand Down Expand Up @@ -348,6 +347,104 @@ gulp.task 'pack:win32:installer', ['build:win32', 'clean:dist:win32'], (done) ->
.then callback, callback
], done

# Create the win32 nsis installer
gulp.task 'pack:win32:nsis', ['build:win32', 'clean:dist:win32'], (done) ->
if process.platform isnt 'win32'
return console.warn 'Skipping win32 NSIS installer packing; This has only been tested on Windows.'

for envName in ['SIGN_WIN_CERTIFICATE_FILE', 'SIGN_WIN_CERTIFICATE_PASSWORD']
if not process.env[envName]
return console.warn envName + ' env var not set.'

async.series [
# Update package.json
async.apply updateManifest, './build/win32/resources/app/package.json', (manifest) ->
manifest.portable = false
manifest.distrib = 'win32:nsis'
manifest.buildNum = process.env.APPVEYOR_BUILD_NUMBER
manifest.dev = false

# Remove the dev modules
applyIf args.prod, applySpawn 'npm', ['prune', '--production'],
cwd: './build/win32/resources/app'

# Deduplicate dependencies
applyIf args.prod, applySpawn 'npm', ['dedupe'],
cwd: './build/win32/resources/app'

# Compress the source files into an asar archive
async.apply asar.createPackage, './build/win32/resources/app', './build/win32/resources/app.asar'

# Remove leftovers
applyPromise del, './build/win32/resources/app'

# Create the installer
(callback) ->
console.log 'creating installer'
signParams = [
'/t'
'http://timestamp.verisign.com/scripts/timstamp.dll'
'/f'
process.env.SIGN_WIN_CERTIFICATE_FILE
'/p'
process.env.SIGN_WIN_CERTIFICATE_PASSWORD
]

remoteReleasesUrl = manifest.updater.urls.win32
.replace /{{& SQUIRREL_UPDATES_URL }}/g, process.env.SQUIRREL_UPDATES_URL
.replace /%CHANNEL%/g, 'dev'
releasesUrl = remoteReleasesUrl + '/RELEASES'

console.log 'creating check request'
request {url: releasesUrl}, (err, res, body) ->
console.log 'request done'

if err or not res or res.statusCode < 200 or res.statusCode >= 400
console.log 'Creating installer without remote releases url', releasesUrl, 'because of',
'error', err, 'statusCode', res and res.statusCode, 'body', res and res.body
remoteReleasesUrl = undefined

console.log 'request ok, running winInstaller'
winInstaller
appDirectory: './build/win32'
outputDirectory: './dist'
loadingGif: './build/resources/win/install-spinner.gif'
signWithParams: signParams.join ' '
setupIcon: './build/resources/win/setup.ico'
iconUrl: mainManifest.icon.url
description: manifest.productName
authors: manifest.authorName
remoteReleases: remoteReleasesUrl
copyright: manifest.copyright
setupExe: manifest.name + '-' + manifest.version + '-win32-setup-for-nsis.exe'
noMsi: true
arch: 'ia32'
.then ->
console.log 'winInstaller done'
callback()
.catch (err) ->
console.log 'winInstaller errored'
callback err

# Run makensis
applySpawn (process.env.MAKENSIS_PATH or 'makensis.exe'), ['build/resources/win/installer.nsi']

# Sign the exe
(callback) ->
cmd = process.env.SIGNTOOL_PATH or 'signtool'
args = [
'sign'
'/t'
'http://timestamp.verisign.com/scripts/timstamp.dll'
'/f'
process.env.SIGN_WIN_CERTIFICATE_FILE
'/p'
process.env.SIGN_WIN_CERTIFICATE_PASSWORD
path.win32.resolve './dist/' + manifest.name + '-' + manifest.version + '-win32-nsis.exe'
]
applySpawn(cmd, args)(callback)
], done

# Create the win32 portable zip
gulp.task 'pack:win32:portable', ['build:win32', 'clean:dist:win32'], (done) ->
if process.platform isnt 'win32'
Expand Down
2 changes: 1 addition & 1 deletion tasks/publish.coffee
Expand Up @@ -175,7 +175,7 @@ gulp.task 'publish:bintray:aur', ->
# Publish AUR package
gulp.task 'publish:aur', ['publish:bintray:aur'], (done) ->
manifest.linux.name = manifest.name
manifest.linux.buildNum = process.env.TRAVIS_BUILD_NUMBER or manifest.buildNum
manifest.linux.buildNum = process.env.CIRCLE_BUILD_NUM or manifest.buildNum
manifest.linux.productName = manifest.productName
manifest.linux.description = manifest.description
manifest.linux.homepage = manifest.homepage
Expand Down
4 changes: 4 additions & 0 deletions tasks/resources.coffee
Expand Up @@ -41,7 +41,11 @@ gulp.task 'resources:linux', ->

# Move the resources for win32
gulp.task 'resources:win', ->
templateFilter = filter ['**/installer.nsi'], {restore: true}
gulp.src './resources/win/**/*'
.pipe templateFilter
.pipe mustache manifest
.pipe templateFilter.restore
.pipe gulp.dest './build/resources/win'

# Move and process resources for the current platform by default
Expand Down