├── .github └── stale.yml ├── .gitignore ├── .npmrc ├── README.md ├── app ├── index.js └── package.json ├── config ├── env_development.json ├── env_production.json └── env_test.json ├── gulpfile.js ├── package.json ├── resources ├── linux │ ├── DEBIAN │ │ └── control │ └── app.desktop ├── osx │ ├── Info.plist │ ├── appdmg.json │ ├── dmg-background.png │ ├── dmg-background@2x.png │ ├── dmg-icon.icns │ ├── helper_apps │ │ ├── Info EH.plist │ │ ├── Info NP.plist │ │ └── Info.plist │ └── icon.icns └── windows │ ├── icon.ico │ ├── installer.nsi │ ├── setup-banner.bmp │ └── setup-icon.ico └── tasks ├── release.js ├── release_linux.js ├── release_osx.js ├── release_windows.js ├── start.js └── utils.js /.github/stale.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | app/node_modules 3 | releases 4 | tmp 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | patchwork-electron 2 | ============== 3 | 4 | 5 | ## Running from source 6 | 7 | ```bash 8 | $ cd ~ 9 | $ git clone https://github.com/ssbc/patchwork-electron.git 10 | $ cd patchwork-electron 11 | $ npm install 12 | $ npm start 13 | ``` 14 | 15 | To use the latest patchwork version, do the following: 16 | 17 | ```bash 18 | $ cd ~ 19 | $ git clone https://github.com/ssbc/patchwork.git 20 | $ cd patchwork 21 | $ npm install 22 | $ npm link 23 | $ cd ~/patchwork-electron/app 24 | $ npm link ssb-patchwork 25 | ``` 26 | 27 | ## Troubleshooting 28 | 29 | If you get an error similar to: 30 | 31 | > Uncaught Exception: 32 | > Error: Module version mismatch. Expected 50, got 48. 33 | 34 | It means your installed node version is not compatible with the version of Electron patchwork uses. You'll need to rebuild your node module folder using: 35 | 36 | ```bash 37 | $ npm run rebuild 38 | ``` 39 | 40 | ## Building 41 | 42 | ```bash 43 | $ npm run release 44 | ``` 45 | 46 | ## More info 47 | 48 | This repo is based on https://github.com/szwacz/electron-boilerplate. 49 | Check that repo to get more information on the structure and scripts. 50 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | require('ssb-patchwork') -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssb-patchwork-electron", 3 | "productName": "Patchwork", 4 | "identifier": "com.ssbc.patchwork", 5 | "description": "p2p social sharing", 6 | "author": "Paul Frazee ", 7 | "copyright": "© 2016, Secure Scuttlebutt Consortium", 8 | "license": "GPL-3.0", 9 | "main": "index.js", 10 | "version": "2.12.4", 11 | "dependencies": { 12 | "ssb-patchwork": "2.12.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config/env_development.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "development", 3 | "description": "Add here any environment specific stuff you like." 4 | } 5 | -------------------------------------------------------------------------------- /config/env_production.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "production", 3 | "description": "Add here any environment specific stuff you like." 4 | } 5 | -------------------------------------------------------------------------------- /config/env_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "description": "Add here any environment specific stuff you like." 4 | } 5 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./tasks/release'); 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "asar": "^0.7.2", 4 | "electron-prebuilt": "1.4.2", 5 | "fs-jetpack": "^0.7.0", 6 | "gulp": "^3.9.0", 7 | "gulp-less": "^3.0.3", 8 | "gulp-util": "^3.0.6", 9 | "prebuild": "^4.2.2", 10 | "q": "^1.4.1", 11 | "rollup": "^0.21.0", 12 | "tree-kill": "^0.1.1", 13 | "yargs": "^3.15.0" 14 | }, 15 | "optionalDependencies": { 16 | "appdmg": "^0.3.2", 17 | "rcedit": "^0.3.0" 18 | }, 19 | "scripts": { 20 | "postinstall": "cd app && npm install && cd .. && npm run rebuild", 21 | "rebuild": "cd app && npm rebuild --runtime=electron --target=1.4.2 --abi=50 --disturl=https://atom.io/download/atom-shell", 22 | "release": "gulp release --env=production", 23 | "start": "node ./tasks/start", 24 | "test": "node ./tasks/start --env=test" 25 | }, 26 | "dependencies": { 27 | "mktemp": "^0.4.0" 28 | }, 29 | "version": "2.12.4" 30 | } 31 | -------------------------------------------------------------------------------- /resources/linux/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: {{name}} 2 | Version: {{version}} 3 | Maintainer: {{author}} 4 | Priority: optional 5 | Architecture: {{arch}} 6 | Installed-Size: {{size}} 7 | Description: {{description}} 8 | -------------------------------------------------------------------------------- /resources/linux/app.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Encoding=UTF-8 5 | Name={{productName}} 6 | Comment={{description}} 7 | Exec=/opt/{{name}}/{{name}} 8 | Path=/opt/{{name}}/ 9 | Icon=/opt/{{name}}/icon.png 10 | Terminal=false 11 | Categories=Network; 12 | -------------------------------------------------------------------------------- /resources/osx/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | {{productName}} 7 | CFBundleExecutable 8 | {{productName}} 9 | CFBundleIconFile 10 | icon.icns 11 | CFBundleIdentifier 12 | {{identifier}} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | {{productName}} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleVersion 20 | {{version}} 21 | CFBundleGetInfoString 22 | {{version}} 23 | LSMinimumSystemVersion 24 | 10.8.0 25 | NSMainNibFile 26 | MainMenu 27 | NSPrincipalClass 28 | AtomApplication 29 | NSSupportsAutomaticGraphicsSwitching 30 | 31 | NSHumanReadableCopyright 32 | {{copyright}} 33 | 34 | 35 | -------------------------------------------------------------------------------- /resources/osx/appdmg.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "{{productName}}", 3 | "icon": "{{dmgIcon}}", 4 | "background": "{{dmgBackground}}", 5 | "icon-size": 128, 6 | "contents": [ 7 | { "x": 410, "y": 220, "type": "link", "path": "/Applications" }, 8 | { "x": 130, "y": 220, "type": "file", "path": "{{appPath}}" } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /resources/osx/dmg-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/osx/dmg-background.png -------------------------------------------------------------------------------- /resources/osx/dmg-background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/osx/dmg-background@2x.png -------------------------------------------------------------------------------- /resources/osx/dmg-icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/osx/dmg-icon.icns -------------------------------------------------------------------------------- /resources/osx/helper_apps/Info EH.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | {{productName}} Helper EH 7 | CFBundleExecutable 8 | {{productName}} Helper EH 9 | CFBundleIdentifier 10 | {{identifier}}.helper.EH 11 | CFBundleName 12 | {{productName}} Helper EH 13 | CFBundlePackageType 14 | APPL 15 | DTSDKName 16 | macosx 17 | LSUIElement 18 | 19 | NSSupportsAutomaticGraphicsSwitching 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /resources/osx/helper_apps/Info NP.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | {{productName}} Helper NP 7 | CFBundleExecutable 8 | {{productName}} Helper NP 9 | CFBundleIdentifier 10 | {{identifier}}.helper.NP 11 | CFBundleName 12 | {{productName}} Helper NP 13 | CFBundlePackageType 14 | APPL 15 | DTSDKName 16 | macosx 17 | LSUIElement 18 | 19 | NSSupportsAutomaticGraphicsSwitching 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /resources/osx/helper_apps/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | {{identifier}}.helper 7 | CFBundleName 8 | {{productName}} Helper 9 | CFBundlePackageType 10 | APPL 11 | DTSDKName 12 | macosx 13 | LSUIElement 14 | 15 | NSSupportsAutomaticGraphicsSwitching 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /resources/osx/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/osx/icon.icns -------------------------------------------------------------------------------- /resources/windows/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/windows/icon.ico -------------------------------------------------------------------------------- /resources/windows/installer.nsi: -------------------------------------------------------------------------------- 1 | ; NSIS packaging/install script 2 | ; Docs: http://nsis.sourceforge.net/Docs/Contents.html 3 | 4 | !include LogicLib.nsh 5 | !include nsDialogs.nsh 6 | 7 | ; -------------------------------- 8 | ; Variables 9 | ; -------------------------------- 10 | 11 | !define dest "{{dest}}" 12 | !define src "{{src}}" 13 | !define name "{{name}}" 14 | !define productName "{{productName}}" 15 | !define author "{{author}}" 16 | !define version "{{version}}" 17 | !define icon "{{icon}}" 18 | !define setupIcon "{{setupIcon}}" 19 | !define banner "{{banner}}" 20 | 21 | !define exec "{{productName}}.exe" 22 | 23 | !define regkey "Software\${productName}" 24 | !define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${productName}" 25 | 26 | !define uninstaller "uninstall.exe" 27 | 28 | ; -------------------------------- 29 | ; Installation 30 | ; -------------------------------- 31 | 32 | Unicode true 33 | SetCompressor /SOLID lzma 34 | 35 | Name "${productName}" 36 | Icon "${setupIcon}" 37 | OutFile "${dest}" 38 | InstallDir "$PROGRAMFILES\${productName}" 39 | InstallDirRegKey HKLM "${regkey}" "" 40 | 41 | RequestExecutionLevel admin 42 | CRCCheck on 43 | SilentInstall normal 44 | 45 | XPStyle on 46 | ShowInstDetails nevershow 47 | AutoCloseWindow false 48 | WindowIcon off 49 | 50 | Caption "${productName} Setup" 51 | ; Don't add sub-captions to title bar 52 | SubCaption 3 " " 53 | SubCaption 4 " " 54 | 55 | Page custom welcome 56 | Page instfiles 57 | 58 | Var Image 59 | Var ImageHandle 60 | 61 | Function .onInit 62 | 63 | ; Extract banner image for welcome page 64 | InitPluginsDir 65 | ReserveFile "${banner}" 66 | File /oname=$PLUGINSDIR\banner.bmp "${banner}" 67 | 68 | FunctionEnd 69 | 70 | ; Custom welcome page 71 | Function welcome 72 | 73 | nsDialogs::Create 1018 74 | 75 | ${NSD_CreateLabel} 185 1u 210 100% "Welcome to ${productName} version ${version} installer.$\r$\n$\r$\nClick install to begin." 76 | 77 | ${NSD_CreateBitmap} 0 0 170 210 "" 78 | Pop $Image 79 | ${NSD_SetImage} $Image $PLUGINSDIR\banner.bmp $ImageHandle 80 | 81 | nsDialogs::Show 82 | 83 | ${NSD_FreeImage} $ImageHandle 84 | 85 | FunctionEnd 86 | 87 | ; Installation declarations 88 | Section "Install" 89 | 90 | WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" 91 | WriteRegStr HKLM "${uninstkey}" "DisplayName" "${productName}" 92 | WriteRegStr HKLM "${uninstkey}" "DisplayIcon" '"$INSTDIR\icon.ico"' 93 | WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' 94 | WriteRegStr HKLM "${uninstkey}" "Publisher" "${author}" 95 | WriteRegStr HKLM "${uninstkey}" "DisplayVersion" "${version}" 96 | 97 | ; Remove all application files copied by previous installation 98 | RMDir /r "$INSTDIR" 99 | 100 | SetOutPath $INSTDIR 101 | 102 | ; Include all files from /build directory 103 | File /r "${src}\*" 104 | 105 | ; Create start menu shortcut 106 | SetShellVarContext all 107 | CreateShortCut "$SMPROGRAMS\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico" 108 | ; Create desktop shortcut 109 | CreateShortCut "$DESKTOP\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico" 110 | 111 | WriteUninstaller "${uninstaller}" 112 | 113 | SectionEnd 114 | 115 | ; -------------------------------- 116 | ; Uninstaller 117 | ; -------------------------------- 118 | 119 | ShowUninstDetails nevershow 120 | 121 | UninstallCaption "Uninstall ${productName}" 122 | UninstallText "Don't like ${productName} anymore? Hit uninstall button." 123 | UninstallIcon "${icon}" 124 | 125 | UninstPage custom un.confirm un.confirmOnLeave 126 | UninstPage instfiles 127 | 128 | Var RemoveAppDataCheckbox 129 | Var RemoveAppDataCheckbox_State 130 | 131 | ; Custom uninstall confirm page 132 | Function un.confirm 133 | 134 | nsDialogs::Create 1018 135 | 136 | ${NSD_CreateLabel} 1u 1u 100% 24u "If you really want to remove ${productName} from your computer press uninstall button." 137 | 138 | ${NSD_CreateCheckbox} 1u 35u 100% 10u "Remove also my ${productName} personal data" 139 | Pop $RemoveAppDataCheckbox 140 | 141 | nsDialogs::Show 142 | 143 | FunctionEnd 144 | 145 | Function un.confirmOnLeave 146 | 147 | ; Save checkbox state on page leave 148 | ${NSD_GetState} $RemoveAppDataCheckbox $RemoveAppDataCheckbox_State 149 | 150 | FunctionEnd 151 | 152 | ; Uninstall declarations 153 | Section "Uninstall" 154 | 155 | DeleteRegKey HKLM "${uninstkey}" 156 | DeleteRegKey HKLM "${regkey}" 157 | 158 | SetShellVarContext all 159 | Delete "$SMPROGRAMS\${productName}.lnk" 160 | ; Remove desktop shortcut 161 | Delete "$DESKTOP\${productName}.lnk" 162 | ; Remove whole directory from Program Files 163 | RMDir /r "$INSTDIR" 164 | 165 | ; Remove also appData directory generated by your app if user checked this option 166 | ${If} $RemoveAppDataCheckbox_State == ${BST_CHECKED} 167 | RMDir /r "$APPDATA\${productName}" 168 | ${EndIf} 169 | 170 | SectionEnd 171 | -------------------------------------------------------------------------------- /resources/windows/setup-banner.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/windows/setup-banner.bmp -------------------------------------------------------------------------------- /resources/windows/setup-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssb-junkyard/patchwork-classic-electron/87e60537ff20aa81f810c07fc01fa1da98d30576/resources/windows/setup-icon.ico -------------------------------------------------------------------------------- /tasks/release.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var utils = require('./utils'); 5 | 6 | var releaseForOs = { 7 | osx: require('./release_osx'), 8 | linux: require('./release_linux'), 9 | windows: require('./release_windows'), 10 | }; 11 | 12 | gulp.task('release', function () { 13 | return releaseForOs[utils.os()](); 14 | }); 15 | -------------------------------------------------------------------------------- /tasks/release_linux.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | var gulpUtil = require('gulp-util'); 5 | var childProcess = require('child_process'); 6 | var jetpack = require('fs-jetpack'); 7 | var asar = require('asar'); 8 | var utils = require('./utils'); 9 | var mktemp = require('mktemp'); 10 | var path = require('path'); 11 | var os = require('os'); 12 | 13 | var projectDir; 14 | var releasesDir; 15 | var packName; 16 | var packDir; 17 | var tmpDir; 18 | var readyAppDir; 19 | var manifest; 20 | var debArch = {x64: 'amd64', ia32: 'i386', arm: 'armhf'}[os.arch()] || os.arch(); 21 | 22 | var init = function () { 23 | projectDir = jetpack; 24 | var tmpDirTemplate = path.join(os.tmpdir(), 'package-XXXXXXXX'); 25 | tmpDir = jetpack.cwd(mktemp.createDirSync(tmpDirTemplate)); 26 | releasesDir = projectDir.dir('./releases'); 27 | manifest = projectDir.read('app/package.json', 'json'); 28 | packName = manifest.name + '_' + manifest.version; 29 | packDir = tmpDir.dir(packName); 30 | readyAppDir = packDir.cwd('opt', manifest.name); 31 | 32 | return Q(); 33 | }; 34 | 35 | var copyRuntime = function () { 36 | projectDir.copy('node_modules/electron-prebuilt/dist', readyAppDir.path(), { overwrite: true }); 37 | 38 | // Add Patchwork's license next to the other licenses 39 | readyAppDir.rename('LICENSE', 'LICENSE-Electron'); 40 | return projectDir.copyAsync('app/node_modules/ssb-patchwork/LICENSE', 41 | readyAppDir.path('LICENSE-Patchwork')); 42 | }; 43 | 44 | var cleanupRuntime = function () { 45 | return readyAppDir.removeAsync('resources/default_app'); 46 | }; 47 | 48 | var packageApp = function () { 49 | var deferred = Q.defer(); 50 | 51 | asar.createPackage(projectDir.path('app'), readyAppDir.path('resources/app.asar'), function () { 52 | deferred.resolve(); 53 | }); 54 | 55 | return deferred.promise; 56 | }; 57 | 58 | var finalize = function () { 59 | // Create .desktop file from the template 60 | var desktop = projectDir.read('resources/linux/app.desktop'); 61 | desktop = utils.replace(desktop, { 62 | name: manifest.name, 63 | productName: manifest.productName, 64 | description: manifest.description, 65 | version: manifest.version, 66 | author: manifest.author 67 | }); 68 | packDir.write('usr/share/applications/' + manifest.name + '.desktop', desktop); 69 | 70 | // Copy icon 71 | projectDir.copy('app/node_modules/ssb-patchwork/ui/img/icon.png', 72 | readyAppDir.path('icon.png')); 73 | 74 | return Q(); 75 | }; 76 | 77 | var renameApp = function () { 78 | return readyAppDir.renameAsync("electron", manifest.name); 79 | }; 80 | 81 | var packToArchive = function () { 82 | var deferred = Q.defer(); 83 | var archiveFileName = packName + '_' + debArch + '.tar.gz'; 84 | var archivePath = releasesDir.path(archiveFileName); 85 | var appContainerDir = packDir.cwd('opt'); 86 | 87 | // Archive the package 88 | childProcess.execFile('tar', ['czf', archivePath, '-C', appContainerDir.path(), '.'], 89 | function (error, stdout, stderr) { 90 | if (error || stderr) { 91 | console.log('ERROR while archiving package:'); 92 | console.log(error); 93 | console.log(stderr); 94 | } else { 95 | gulpUtil.log('Archive ready', archivePath); 96 | } 97 | deferred.resolve(); 98 | }); 99 | 100 | return deferred.promise; 101 | } 102 | 103 | var packToDebFile = function () { 104 | var deferred = Q.defer(); 105 | 106 | var debFileName = packName + '_' + debArch + '.deb'; 107 | var debPath = releasesDir.path(debFileName); 108 | 109 | gulpUtil.log('Creating DEB package...'); 110 | 111 | // Counting size of the app in KiB 112 | var appSize = Math.round(readyAppDir.inspectTree('.').size / 1024); 113 | 114 | // Preparing debian control file 115 | var control = projectDir.read('resources/linux/DEBIAN/control'); 116 | control = utils.replace(control, { 117 | name: manifest.name, 118 | description: manifest.description, 119 | version: manifest.version, 120 | author: manifest.author, 121 | arch: debArch, 122 | size: appSize 123 | }); 124 | packDir.write('DEBIAN/control', control); 125 | 126 | // Build the package... 127 | childProcess.exec('fakeroot dpkg-deb -Zxz --build ' + packDir.path().replace(/\s/g, '\\ ') + ' ' + debPath.replace(/\s/g, '\\ '), 128 | function (error, stdout, stderr) { 129 | if (error || stderr) { 130 | console.log("ERROR while building DEB package:"); 131 | console.log(error); 132 | console.log(stderr); 133 | } else { 134 | gulpUtil.log('DEB package ready!', debPath); 135 | } 136 | deferred.resolve(); 137 | }); 138 | 139 | return deferred.promise; 140 | }; 141 | 142 | var cleanClutter = function () { 143 | return tmpDir.removeAsync('.'); 144 | }; 145 | 146 | module.exports = function () { 147 | return init() 148 | .then(copyRuntime) 149 | .then(cleanupRuntime) 150 | .then(packageApp) 151 | .then(finalize) 152 | .then(renameApp) 153 | .then(packToArchive) 154 | .then(packToDebFile) 155 | .then(cleanClutter) 156 | .catch(console.error); 157 | }; 158 | -------------------------------------------------------------------------------- /tasks/release_osx.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | var gulpUtil = require('gulp-util'); 5 | var jetpack = require('fs-jetpack'); 6 | var asar = require('asar'); 7 | var utils = require('./utils'); 8 | var child_process = require('child_process'); 9 | 10 | var projectDir; 11 | var releasesDir; 12 | var tmpDir; 13 | var finalAppDir; 14 | var manifest; 15 | 16 | var init = function () { 17 | projectDir = jetpack; 18 | tmpDir = projectDir.dir('./tmp', { empty: true }); 19 | releasesDir = projectDir.dir('./releases'); 20 | manifest = projectDir.read('app/package.json', 'json'); 21 | finalAppDir = tmpDir.cwd(manifest.productName + '.app'); 22 | 23 | return Q(); 24 | }; 25 | 26 | var copyRuntime = function () { 27 | return projectDir.copyAsync('node_modules/electron-prebuilt/dist/Electron.app', finalAppDir.path()); 28 | }; 29 | 30 | var cleanupRuntime = function () { 31 | finalAppDir.remove('Contents/Resources/default_app'); 32 | finalAppDir.remove('Contents/Resources/atom.icns'); 33 | return Q(); 34 | }; 35 | 36 | var packageApp = function () { 37 | var deferred = Q.defer(); 38 | 39 | asar.createPackage(projectDir.path('app'), finalAppDir.path('Contents/Resources/app.asar'), function () { 40 | deferred.resolve(); 41 | }); 42 | 43 | return deferred.promise; 44 | }; 45 | 46 | var finalize = function () { 47 | // Prepare main Info.plist 48 | var info = projectDir.read('resources/osx/Info.plist'); 49 | info = utils.replace(info, { 50 | productName: manifest.productName, 51 | identifier: manifest.identifier, 52 | version: manifest.version, 53 | copyright: manifest.copyright 54 | }); 55 | finalAppDir.write('Contents/Info.plist', info); 56 | 57 | // Prepare Info.plist of Helper apps 58 | [' EH', ' NP', ''].forEach(function (helper_suffix) { 59 | info = projectDir.read('resources/osx/helper_apps/Info' + helper_suffix + '.plist'); 60 | info = utils.replace(info, { 61 | productName: manifest.productName, 62 | identifier: manifest.identifier 63 | }); 64 | finalAppDir.write('Contents/Frameworks/Electron Helper' + helper_suffix + '.app/Contents/Info.plist', info); 65 | }); 66 | 67 | // Copy icon 68 | projectDir.copy('resources/osx/icon.icns', finalAppDir.path('Contents/Resources/icon.icns')); 69 | 70 | return Q(); 71 | }; 72 | 73 | var renameApp = function () { 74 | // Rename helpers 75 | [' Helper EH', ' Helper NP', ' Helper'].forEach(function (helper_suffix) { 76 | finalAppDir.rename('Contents/Frameworks/Electron' + helper_suffix + '.app/Contents/MacOS/Electron' + helper_suffix, manifest.productName + helper_suffix ); 77 | finalAppDir.rename('Contents/Frameworks/Electron' + helper_suffix + '.app', manifest.productName + helper_suffix + '.app'); 78 | }); 79 | // Rename application 80 | finalAppDir.rename('Contents/MacOS/Electron', manifest.productName); 81 | return Q(); 82 | }; 83 | 84 | var signApp = function () { 85 | var identity = utils.getSigningId(); 86 | if (identity) { 87 | var cmd = 'codesign --deep --force --sign "' + identity + '" "' + finalAppDir.path() + '"'; 88 | gulpUtil.log('Signing with:', cmd); 89 | return Q.nfcall(child_process.exec, cmd); 90 | } else { 91 | return Q(); 92 | } 93 | }; 94 | 95 | var packToDmgFile = function () { 96 | var deferred = Q.defer(); 97 | 98 | var appdmg = require('appdmg'); 99 | var dmgName = manifest.name + '_' + manifest.version + '.dmg'; 100 | 101 | // Prepare appdmg config 102 | var dmgManifest = projectDir.read('resources/osx/appdmg.json'); 103 | dmgManifest = utils.replace(dmgManifest, { 104 | productName: manifest.productName, 105 | appPath: finalAppDir.path(), 106 | dmgIcon: projectDir.path("resources/osx/dmg-icon.icns"), 107 | dmgBackground: projectDir.path("resources/osx/dmg-background.png") 108 | }); 109 | tmpDir.write('appdmg.json', dmgManifest); 110 | 111 | // Delete DMG file with this name if already exists 112 | releasesDir.remove(dmgName); 113 | 114 | gulpUtil.log('Packaging to DMG file...'); 115 | 116 | var readyDmgPath = releasesDir.path(dmgName); 117 | appdmg({ 118 | source: tmpDir.path('appdmg.json'), 119 | target: readyDmgPath 120 | }) 121 | .on('error', function (err) { 122 | console.error(err); 123 | }) 124 | .on('finish', function () { 125 | gulpUtil.log('DMG file ready!', readyDmgPath); 126 | deferred.resolve(); 127 | }); 128 | 129 | return deferred.promise; 130 | }; 131 | 132 | var cleanClutter = function () { 133 | return tmpDir.removeAsync('.'); 134 | }; 135 | 136 | module.exports = function () { 137 | return init() 138 | .then(copyRuntime) 139 | .then(cleanupRuntime) 140 | .then(packageApp) 141 | .then(finalize) 142 | .then(renameApp) 143 | .then(signApp) 144 | .then(packToDmgFile) 145 | .then(cleanClutter) 146 | .catch(console.error); 147 | }; 148 | -------------------------------------------------------------------------------- /tasks/release_windows.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Q = require('q'); 4 | var gulpUtil = require('gulp-util'); 5 | var childProcess = require('child_process'); 6 | var jetpack = require('fs-jetpack'); 7 | var asar = require('asar'); 8 | var utils = require('./utils'); 9 | 10 | var projectDir; 11 | var tmpDir; 12 | var releasesDir; 13 | var readyAppDir; 14 | var manifest; 15 | 16 | var init = function () { 17 | projectDir = jetpack; 18 | tmpDir = projectDir.dir('./tmp', { empty: true }); 19 | releasesDir = projectDir.dir('./releases'); 20 | manifest = projectDir.read('app/package.json', 'json'); 21 | readyAppDir = tmpDir.cwd(manifest.name); 22 | 23 | return Q(); 24 | }; 25 | 26 | var copyRuntime = function () { 27 | return projectDir.copyAsync('node_modules/electron-prebuilt/dist', readyAppDir.path(), { overwrite: true }); 28 | }; 29 | 30 | var cleanupRuntime = function () { 31 | return readyAppDir.removeAsync('resources/default_app'); 32 | }; 33 | 34 | var packageApp = function () { 35 | var deferred = Q.defer(); 36 | 37 | asar.createPackage(projectDir.path('app'), readyAppDir.path('resources/app.asar'), function () { 38 | deferred.resolve(); 39 | }); 40 | 41 | return deferred.promise; 42 | }; 43 | 44 | var finalize = function () { 45 | var deferred = Q.defer(); 46 | 47 | projectDir.copy('resources/windows/icon.ico', readyAppDir.path('icon.ico')); 48 | 49 | // Replace Electron icon for your own. 50 | var rcedit = require('rcedit'); 51 | rcedit(readyAppDir.path('electron.exe'), { 52 | 'icon': projectDir.path('resources/windows/icon.ico'), 53 | 'version-string': { 54 | 'ProductName': manifest.productName, 55 | 'FileDescription': manifest.description, 56 | 'ProductVersion': manifest.version, 57 | 'CompanyName': manifest.author, // it might be better to add another field to package.json for this 58 | 'LegalCopyright': manifest.copyright, 59 | 'OriginalFilename': manifest.productName + '.exe' 60 | } 61 | }, function (err) { 62 | if (!err) { 63 | deferred.resolve(); 64 | } 65 | }); 66 | 67 | return deferred.promise; 68 | }; 69 | 70 | var renameApp = function () { 71 | return readyAppDir.renameAsync('electron.exe', manifest.productName + '.exe'); 72 | }; 73 | 74 | var createInstaller = function () { 75 | var deferred = Q.defer(); 76 | 77 | var finalPackageName = manifest.name + '_' + manifest.version + '.exe'; 78 | var installScript = projectDir.read('resources/windows/installer.nsi'); 79 | 80 | installScript = utils.replace(installScript, { 81 | name: manifest.name, 82 | productName: manifest.productName, 83 | author: manifest.author, 84 | version: manifest.version, 85 | src: readyAppDir.path(), 86 | dest: releasesDir.path(finalPackageName), 87 | icon: readyAppDir.path('icon.ico'), 88 | setupIcon: projectDir.path('resources/windows/setup-icon.ico'), 89 | banner: projectDir.path('resources/windows/setup-banner.bmp'), 90 | }); 91 | tmpDir.write('installer.nsi', installScript); 92 | 93 | gulpUtil.log('Building installer with NSIS...'); 94 | 95 | // Remove destination file if already exists. 96 | releasesDir.remove(finalPackageName); 97 | 98 | // Note: NSIS have to be added to PATH (environment variables). 99 | var nsis = childProcess.spawn('makensis', [ 100 | tmpDir.path('installer.nsi') 101 | ], { 102 | stdio: 'inherit' 103 | }); 104 | nsis.on('error', function (err) { 105 | if (err.message === 'spawn makensis ENOENT') { 106 | throw "Can't find NSIS. Are you sure you've installed it and" 107 | + " added to PATH environment variable?"; 108 | } else { 109 | throw err; 110 | } 111 | }); 112 | nsis.on('close', function () { 113 | gulpUtil.log('Installer ready!', releasesDir.path(finalPackageName)); 114 | deferred.resolve(); 115 | }); 116 | 117 | return deferred.promise; 118 | }; 119 | 120 | var cleanClutter = function () { 121 | return tmpDir.removeAsync('.'); 122 | }; 123 | 124 | module.exports = function () { 125 | return init() 126 | .then(copyRuntime) 127 | .then(cleanupRuntime) 128 | .then(packageApp) 129 | .then(finalize) 130 | .then(renameApp) 131 | .then(createInstaller) 132 | .then(cleanClutter) 133 | .catch(console.error); 134 | }; 135 | -------------------------------------------------------------------------------- /tasks/start.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var electron = require('electron-prebuilt'); 4 | var childProcess = require('child_process'); 5 | 6 | var app = childProcess.spawn(electron, ['./app'], { 7 | stdio: 'inherit' 8 | }); 9 | 10 | app.on('close', function (code) { 11 | // User closed the app. Kill the host process. 12 | process.exit(); 13 | }); -------------------------------------------------------------------------------- /tasks/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var argv = require('yargs').argv; 4 | var os = require('os'); 5 | var jetpack = require('fs-jetpack'); 6 | 7 | module.exports.os = function () { 8 | switch (os.platform()) { 9 | case 'darwin': 10 | return 'osx'; 11 | case 'linux': 12 | return 'linux'; 13 | case 'win32': 14 | return 'windows'; 15 | } 16 | return 'unsupported'; 17 | }; 18 | 19 | module.exports.replace = function (str, patterns) { 20 | Object.keys(patterns).forEach(function (pattern) { 21 | var matcher = new RegExp('{{' + pattern + '}}', 'g'); 22 | str = str.replace(matcher, patterns[pattern]); 23 | }); 24 | return str; 25 | }; 26 | 27 | module.exports.getEnvName = function () { 28 | return argv.env || 'development'; 29 | }; 30 | 31 | module.exports.getSigningId = function () { 32 | return argv.sign; 33 | }; 34 | 35 | module.exports.getElectronVersion = function () { 36 | var manifest = jetpack.read(__dirname + '/../package.json', 'json'); 37 | return manifest.devDependencies['electron-prebuilt'].substring(1); 38 | }; 39 | --------------------------------------------------------------------------------