From 51acbaaa9caf210ba7bdbc3d3c236b5d763269c4 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Fri, 29 Jan 2016 11:37:54 +0800 Subject: [PATCH] Cleanup options.js, rename `--app-name` to `--name` --- README.md | 13 ++- package.json | 2 +- src/buildApp.js | 20 +---- src/cli.js | 4 +- src/helpers.js | 1 + src/{ => infer}/inferIcon.js | 0 src/infer/inferOs.js | 24 ++++++ src/infer/inferTitle.js | 25 ++++++ src/options.js | 154 +++++++++++------------------------ test/module/index-spec.js | 2 +- 10 files changed, 112 insertions(+), 133 deletions(-) rename src/{ => infer}/inferIcon.js (100%) create mode 100644 src/infer/inferOs.js create mode 100644 src/infer/inferTitle.js diff --git a/README.md b/README.md index 6846ff7..ed40691 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Nativefier [![Build Status](https://travis-ci.org/jiahaog/nativefier.svg?branch=master)](https://travis-ci.org/jiahaog/nativefier) [![npm version](https://badge.fury.io/js/nativefier.svg)](https://www.npmjs.com/package/nativefier) + ![Dock Screenshot](https://raw.githubusercontent.com/jiahaog/nativefier/master/screenshots/Dock%20Screenshot.png) You want to make a native wrapper for Google Maps (or any web page). @@ -19,6 +20,10 @@ I did this because I was tired of having to `⌘-tab` or `alt-tab` to my browser View the changelog [here](https://github.com/jiahaog/nativefier/blob/master/History.md). +### Features + +- Automatically retrieves the correct icon and app name + ## Installation With [Node.js](https://nodejs.org/) installed, @@ -54,10 +59,10 @@ Creating a native desktop app for [medium.com](http://medium.com): $ nativefier "http://medium.com" ``` -Nativefier will intelligently attempt to determine the app name, your OS and processor architecture, among other options. If desired, the app name or other options can be overwritten by specifying the `--app-name "Medium"` as part of the command line options, as such. +Nativefier will intelligently attempt to determine the app name, your OS and processor architecture, among other options. If desired, the app name or other options can be overwritten by specifying the `--name "Medium"` as part of the command line options, as such. ``` -$ nativefier --app-name "Some Awesome App" "http://medium.com" +$ nativefier --name "Some Awesome App" "http://medium.com" ``` **For Windows Users:** Take note that the application menu is automatically hidden by default, you can press `alt` on your keyboard to access it. @@ -85,10 +90,10 @@ Specifies the destination directory to build the app to, defaults to the current Prints the usage information. -#### [app-name] +#### [name] ``` --n, --app-name +-n, --name ``` The name of the application, which will affect strings in titles and the icon. diff --git a/package.json b/package.json index 3d91d6e..1beb5dc 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "clean": "gulp clean", "build": "gulp build", "watch": "while true ; do gulp watch ; done", - "package-placeholder": "npm run build && node lib/cli.js http://www.bennish.net/web-notifications.html ~/Desktop --overwrite --app-name notification-test --icon ./test-resources/iconSampleGrey.png && open ~/Desktop/notification-test-darwin-x64/notification-test.app", + "package-placeholder": "npm run build && node lib/cli.js http://www.bennish.net/web-notifications.html ~/Desktop --overwrite --name notification-test --icon ./test-resources/iconSampleGrey.png && open ~/Desktop/notification-test-darwin-x64/notification-test.app", "start-placeholder": "npm run build && electron app", "release": "gulp release" }, diff --git a/src/buildApp.js b/src/buildApp.js index fe003d7..0fddbf4 100644 --- a/src/buildApp.js +++ b/src/buildApp.js @@ -36,24 +36,7 @@ function buildApp(options, callback) { async.waterfall([ callback => { - optionsFactory( - options.appName, - options.targetUrl, - options.platform, - options.arch, - options.electronVersion, - options.outDir, - options.overwrite, - options.conceal, - options.icon, - options.counter, - options.width, - options.height, - options.showMenuBar, - options.userAgent, - options.honest, - options.insecure, - callback); + optionsFactory(options, callback); }, (options, callback) => { copyPlaceholderApp(options.dir, tmpPath, options.name, options.targetUrl, options.counter, options.width, options.height, options.showMenuBar, options.userAgent, options.insecure, (error, tempDirPath) => { @@ -70,7 +53,6 @@ function buildApp(options, callback) { // maybe skip passing icon parameter to electron packager const packageOptions = maybeNoIconOption(options); - packager(packageOptions, (error, appPathArray) => { // pass options which still contains the icon to waterfall callback(error, options, appPathArray); diff --git a/src/cli.js b/src/cli.js index 09748d7..132d614 100755 --- a/src/cli.js +++ b/src/cli.js @@ -13,9 +13,9 @@ if (require.main === module) { .arguments(' [dest]') .action(function(targetUrl, appDir) { program.targetUrl = targetUrl; - program.outDir = appDir; + program.out = appDir; }) - .option('-n, --app-name ', 'app name') + .option('-n, --name ', 'app name') .option('-p, --platform ', '\'linux\', \'win32\', or \'darwin\'') .option('-a, --arch ', '\'ia32\' or \'x64\'') .option('-e, --electron-version ', 'electron version to package, without the \'v\', see https://github.com/atom/electron/releases') diff --git a/src/helpers.js b/src/helpers.js index da01e11..d4dba7d 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -7,6 +7,7 @@ function isOSX() { function isWindows() { return os.platform() === 'windows'; } + export default { isOSX: isOSX, isWindows: isWindows diff --git a/src/inferIcon.js b/src/infer/inferIcon.js similarity index 100% rename from src/inferIcon.js rename to src/infer/inferIcon.js diff --git a/src/infer/inferOs.js b/src/infer/inferOs.js new file mode 100644 index 0000000..b6846a8 --- /dev/null +++ b/src/infer/inferOs.js @@ -0,0 +1,24 @@ +import os from 'os'; + +function inferPlatform() { + const platform = os.platform(); + if (platform === 'darwin' || platform === 'win32' || platform === 'linux') { + return platform; + } + + console.warn(`Warning: Untested platform ${platform} detected, assuming linux`); + return 'linux'; +} + +function inferArch() { + const arch = os.arch(); + if (arch !== 'ia32' && arch !== 'x64') { + throw `Incompatible architecture ${arch} detected`; + } + return arch; +} + +export default { + inferPlatform: inferPlatform, + inferArch: inferArch +}; diff --git a/src/infer/inferTitle.js b/src/infer/inferTitle.js new file mode 100644 index 0000000..580ab6c --- /dev/null +++ b/src/infer/inferTitle.js @@ -0,0 +1,25 @@ +import request from 'request'; +import cheerio from 'cheerio'; + +function inferTitle(url, callback) { + const options = { + url: url, + headers: { + // fake a user agent because pages like http://messenger.com will throw 404 error + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36' + } + }; + + request(options, (error, response, body) => { + if (error || response.statusCode !== 200) { + callback(`Request Error: ${error}, Status Code ${response ? response.statusCode : 'No Response'}`); + return; + } + + const $ = cheerio.load(body); + const pageTitle = $('title').text().replace(/\//g, ''); + callback(null, pageTitle); + }); +} + +export default inferTitle; diff --git a/src/options.js b/src/options.js index d7a3846..06a7452 100644 --- a/src/options.js +++ b/src/options.js @@ -1,80 +1,61 @@ import os from 'os'; import path from 'path'; import url from 'url'; - -import request from 'request'; -import cheerio from 'cheerio'; import validator from 'validator'; -import sanitize from 'sanitize-filename'; +import sanitizeFilename from 'sanitize-filename'; import _ from 'lodash'; import async from 'async'; -import inferIcon from './inferIcon'; + +import inferIcon from './infer/inferIcon'; +import inferTitle from './infer/inferTitle'; +import inferOs from './infer/inferOs'; + +const {inferPlatform, inferArch} = inferOs; const TEMPLATE_APP_DIR = path.join(__dirname, '../', 'app'); const ELECTRON_VERSION = '0.36.4'; const DEFAULT_APP_NAME = 'APP'; -function optionsFactory(name, - targetUrl, - platform = detectPlatform(), - arch = detectArch(), - version = ELECTRON_VERSION, - outDir = process.cwd(), - overwrite = false, - conceal = false, - icon, - counter = false, - width = 1280, - height = 800, - showMenuBar = false, - userAgent, - honest = false, - insecure = false, - callback) { - targetUrl = normalizeUrl(targetUrl); +/** + * @callback optionsCallback + * @param error + * @param options augmented options + */ - if (!width) { - width = 1280; - } - - if (!height) { - height = 800; - } - - if (!userAgent && !honest) { - userAgent = getFakeUserAgent(); - } +/** + * Extracts only desired keys from inpOptions and augments it with defaults + * @param inpOptions + * @param {optionsCallback} callback + */ +function optionsFactory(inpOptions, callback) { const options = { dir: TEMPLATE_APP_DIR, - - name: name, - targetUrl: targetUrl, - - platform: platform, - arch: arch, - version: version, - - out: outDir, - - // optionals - overwrite: overwrite, - asar: conceal, - icon: icon, - - // app configuration - counter: counter, - width: width, - height: height, - showMenuBar: showMenuBar, - userAgent: userAgent, - insecure: insecure + name: inpOptions.name, + targetUrl: normalizeUrl(inpOptions.targetUrl), + platform: inpOptions.platform || inferPlatform(), + arch: inpOptions.arch || inferArch(), + version: ELECTRON_VERSION, + out: inpOptions.out|| process.cwd(), + overwrite: inpOptions.overwrite || false, + asar: inpOptions.conceal || false, + icon: inpOptions.icon, + counter: inpOptions.counter || false, + width: inpOptions.width || 1280, + height: inpOptions.height || 800, + showMenuBar: inpOptions.showMenuBar || false, + userAgent: inpOptions.userAgent || getFakeUserAgent(), + insecure: inpOptions.insecure || false }; + if (inpOptions.honest) { + options.userAgent = null; + } + async.waterfall([ callback => { if (options.icon) { - callback(null, options); + callback(); return; } inferIcon(options.targetUrl, (error, pngPath) => { @@ -83,80 +64,41 @@ function optionsFactory(name, } else { options.icon = pngPath; } - callback(null, options); + callback(); }); }, - (options, callback) => { - if (name && name.length > 0) { - options.name = name; - callback(null, options); + callback => { + if (options.name && options.name.length > 0) { + callback(); return; } - getTitle(options.targetUrl, function(error, pageTitle) { + inferTitle(options.targetUrl, function(error, pageTitle) { if (error) { console.warn(`Unable to automatically determine app name, falling back to '${DEFAULT_APP_NAME}'`); options.name = DEFAULT_APP_NAME; } else { options.name = pageTitle; } - - callback(null, options); + callback(); }); } - ], (error, options) => { + ], error => { callback(error, sanitizeOptions(options)); + console.log(options); }); } function sanitizeOptions(options) { - options.name = sanitize(options.name); + options.name = sanitizeFilename(options.name); if (options.platform === 'linux') { + // spaces will cause problems with Ubuntu when pinned to the dock options.name = _.kebabCase(options.name); } return options; } -function detectPlatform() { - const platform = os.platform(); - if (platform === 'darwin' || platform === 'win32' || platform === 'linux') { - return platform; - } - - console.warn(`Warning: Untested platform ${platform} detected, assuming linux`); - return 'linux'; -} - -function detectArch() { - const arch = os.arch(); - if (arch !== 'ia32' && arch !== 'x64') { - throw `Incompatible architecture ${arch} detected`; - } - return os.arch(); -} - -function getTitle(url, callback) { - const options = { - url: url, - headers: { - // fake a user agent because pages like http://messenger.com will throw 404 error - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36' - } - }; - - request(options, (error, response, body) => { - if (error || response.statusCode !== 200) { - callback(`Request Error: ${error}, Status Code ${response ? response.statusCode : 'No Response'}`); - return; - } - - const $ = cheerio.load(body); - const pageTitle = $('title').text().replace(/\//g, ''); - callback(null, pageTitle); - }); -} - function normalizeUrl(testUrl) { // add protocol if protocol not found let normalized = testUrl; diff --git a/test/module/index-spec.js b/test/module/index-spec.js index 1fa8cdf..b49afe3 100644 --- a/test/module/index-spec.js +++ b/test/module/index-spec.js @@ -49,7 +49,7 @@ describe('Nativefier Module', function() { const tmpPath = tmpObj.name; const options = { - appName: 'google-test-app', + name: 'google-test-app', targetUrl: 'http://google.com', outDir: tmpPath, overwrite: true,